|
Hi,
I have the following demo code:
[Serializable]
[DataContract(Name = "A", Namespace = "")]
[KnownType(typeof(B))]
public class A
{
public A()
{
Id = 0;
b = new B();
}
[Key]
[DataMember]
public int Id { get; set; }
[DataMember]
public B b { get; set; }
}
[Serializable]
[DataContract(Name = "B", Namespace = "")]
public partial class B : ComplexObject
{
public B()
{
Id = 0;
Description = string.Empty;
}
[Key]
[DataMember]
public int Id { get; set; }
[DataMember]
public string Description { get; set; }
}
The problem that I am having is that the RIA service is only generating the following object:
/// <summary>
/// The 'A' entity class.
/// </summary>
[DataContract(Namespace="", Name="A")]
public sealed partial class A : Entity
{
private int _id;
#region Extensibility Method Definition
#endregion
Can anyone please help me fix this problem, or explain why it does not generate the custom "B" Property?
Thanks
|
|
|
|
|
I've got a treeview containing hyperlinks. Their source is a NodeModel.
<HierarchicalDataTemplate DataType="{x:Type models:NodeModel}"
ItemsSource="{Binding Path=Children}">
<StackPanel Orientation="Horizontal"
Margin="2">
<TextBlock Margin="0,0,5,0">
<Hyperlink NavigateUri="{Binding Caption}"
Foreground="#0C2DAA"
Command="{Binding Path=DataContext.SelectedLinkCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={ x:Type views:ProjectListView}}}">
.
.
.
The hyperlink is bound to a command:
private ICommand _SelectedLinkCommand;
public ICommand SelectedLinkCommand
{
get
{
if (_SelectedLinkCommand == null)
_SelectedLinkCommand = new RelayCommand(SelectedLinkExecuted, SelectedLinkCanExecute);
return _SelectedLinkCommand;
}
}
and the command methods:
private bool SelectedLinkCanExecute()
{
return true;
}
private void SelectedLinkExecuted()
{
}
In the SelectedLinkExecuted method, how can I get a reference to the NodeModel?
Thanks
Everything makes sense in someone's mind
|
|
|
|
|
Collin Jasnoch wrote:
The problem is getting the item. If you can find a way to get it you can pass it in using RelayComman<T>
There is no 'problem' involved in getting the item. You guys are half way to the 'correct' solution:
1) you are correct in that you have the VM expose a RelayCommand<T>. T in this case is going to be RoutedPropertyChangedEventArgs<object>.
2) the part of the puzzle that you guys are missing is an event to command mapper that is capable of forwarding the EventArgs as a command parameter.
#2 is absolutely necessary if you are writing a real MVVM app. How else are you going to forward control events to your VM?
The one I use in my MVVM framework is based off of MVVMLight's EventToCommand class. You simply create an interaction trigger for the event you are trapping and use the EventToCommand class to map it to the command and set the ForwardEventArgs=true. All via XAML.
|
|
|
|
|
Oh, my bad, I misread the OPs post. I originally read it as he was trying to click on the TreeViewItem node. He is not, so there is a much simpler way. My EventToCommand answer still stands as the "proper" way to forward control events to the VM, but that is not needed in this case.
For the sake of argument, here is how you would use the EventToCommand class:
<i:Interaction.Triggers>
<i:EventTrigger EventName="ItemKeyDown">
<wfx:EventToCommand Command="{Binding ElementName=stateCountyCtrl, Path=DataContext.KeyDownCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
You would put that in whatever object owned the event.
Then your RelayCommand<T> (the KeyDownCommand here) would take whatever EventArgs type the event is raising.
See my other response to the OP for the "correct" answer in this case.
|
|
|
|
|
Disregard the other responses in this thread as I misread your original post and thought you were trying to get the EventArgs into your VM.
In this case, you would switch your RelayCommand to RelayCommand<T> where T is NodeModel.
In your XAML, you would simply pass in the NodeModel via the CommandParameter. Add this to your Hyperlink:
CommandParameter="{Binding}"
|
|
|
|
|
This may be rather long. Please bear with me.
I am working on a WPF app. I am trying very hard to follow MVVM design practices as I understand them.
The MainWindow contains a TabControl. For each TabItem, I have created a separate UserControl in order to split things out logically and to make the XAML more manageable (there are going to be several tabs).
Each UserControl has its own ViewModel, which is instantiated in the code behind for the particular UserControl. Each UserControl/ViewModel pair is pretty much self-contained, independent of the others. There is a common Model for all of the above that handles the database end of things (each ViewModel talks to its own instance of the Model). The MainWindow does NOT have a MainWindowViewModel as I have found no need for it (all the MainWindow does is hold a text heading and the TabControl).
The thing that I am wrestling with is this: I would like to be able to prompt the end user to save any pending changes if they click into a different tab. Apparently, whenever you click on a different tab, the TabControl unloads the UserControl of the previously selected tab. The only event that seems to let me know that the user has clicked away into another tab is the Unloaded event for the UserControl. At that point, it appears to be too late to pop up a message from the User Control because it has, well, unloaded.
I discovered that I can handle the SelectionChanged event for the TabControl in the MainWindow, but the way my code is structured, there is no way to get back to the ViewModel of the tab that was deselected to make it save the changes from there.
Suggestions please...
WE ARE DYSLEXIC OF BORG. Refutance is systile. Your a$$ will be laminated.
There are 10 kinds of people in the world: People who know binary and people who don't.
|
|
|
|
|
There is a *gotcha* to this approach though (actually, there are a couple). First of all, when the selection changes, the TabControl has the unfortunate habit of unloading the View (hence unloading the DataContext), and rendering the new view. Second, how does he know that there's unsaved information - this relies on the binding being refreshed, which in turn, relies on the property update mechanism (in other words, is he relying on the focus being lost before the property updates).
|
|
|
|
|
Thanks Pete.
If there was just an "UnloadedPreview" event...
WE ARE DYSLEXIC OF BORG. Refutance is systile. Your a$$ will be laminated.
There are 10 kinds of people in the world: People who know binary and people who don't.
|
|
|
|
|
Collin Jasnoch wrote: I think you and I conversed about this before (I believe you have a blog post
about using IEditableObject... It might have been someone else though).
No, you're right - it was me.
As for the other part, I'm sorry - I misunderstood what you'd pointed out - you're entirely right that the previously selected value will be in there. I glossed right over you talking about needing a main VM, so I apologise; I really should read things more carefully.
|
|
|
|
|
Collin Jasnoch wrote: As for how to know if there is unsaved information, I did breeze over that. I guess I assumed he had some sort of business object tracking that (bad assumption though).
I'm using DevForce for the Model end of things. I can tell if there is unsaved data or not. That should not be a problem.
Collin Jasnoch wrote: I think you and I conversed about this before (I believe you have a blog post about using IEditableObject... It might have been someone else though). He of course needs to be doing something along those lines in order to properly prompt the user. Perhaps you could share that posting with him.
I would be interested in seeing that discussion.
[Edit: Pete gave me the link.]
WE ARE DYSLEXIC OF BORG. Refutance is systile. Your a$$ will be laminated.
There are 10 kinds of people in the world: People who know binary and people who don't.
|
|
|
|
|
Thanks Collin.
Thanks for the tip. Sounds like I need to seriously rethink my way of doing things. You have given me food for thought.
WE ARE DYSLEXIC OF BORG. Refutance is systile. Your a$$ will be laminated.
There are 10 kinds of people in the world: People who know binary and people who don't.
|
|
|
|
|
Tom - the IEditableObject info that Collin was talking about was covered in a blog post that I wrote here[^].
|
|
|
|
|
Thanks Pete.
WE ARE DYSLEXIC OF BORG. Refutance is systile. Your a$$ will be laminated.
There are 10 kinds of people in the world: People who know binary and people who don't.
|
|
|
|
|
No problem. Glad to be able to help.
|
|
|
|
|
Collin,
I've been mulling over your post. It has brought more questions to mind. (Sorry. ) Let me preface what follows with: If I ask something really obvious or stupid, please forgive me. I have been programming for quite a few years, but I am a WPF neophyte. Ditto, if I use the wrong terminology for something. I'm not a GUI programmer ( ), but I am the only PC programmer in our group, and have been forced to jump into this with both feet. I don't really mind as I like to learn new things, but the WPF / MVVM learning curve has been frustrating for me.
Collin Jasnoch wrote: If you had a MainViewModel then the TabControl could have its ItemSource bound to a collection of your viewmodels (the data contexts of the Tabs).
The Tab Control can also maintain binding of "SelectedItem". When it changes you could then run any logic you wanted to (prompt user to save etc.)
That sounds very sensible to me. Obviously (?) my ViewModels are not exactly the same. I guess I should find what is common among them and turn that into a base class (yeah, I should have done that from the outset) that they are all derived from, so that I can create an ObservableCollection of the base class objects? Since the ItemSource is bound to the ObservableCollection, this would take care of setting the DataContext for each TabItem?
Collin Jasnoch wrote: If you choose this path, rather than having the View instantiate the VM*, the MainVM does the work. Then you just need to tell the renderer how to render the object using DataTemplates.
Right now, each TabItem in my TabControl is populated with a separate (but very similar) UserControl that consists of a 3 column Grid with a ListBox in column 0, a GridSplitter in column 1, and another Grid in Column 2. The second Grid in column 2 is a 3 row Grid with the first row containing a TextBlock that is basically a header, the 2nd row containing various TextBlocks and TextBoxes for displaying/entering data, and the last row holding several Buttons. Clicking on an item in the ListBox on the left brings up the corresponding data in the fields on the right.
How would I turn this into a DataTemplate? What about the buttons?
Collin Jasnoch wrote: I prefer this method (VM before View*) as it seems cleaner to me (no code behind)
Dumb question: isn't a certain amount of code behind unavoidable? Like for Button Click and other event handlers? I have been trying to keep what I do there to a bare minimum (i.e. the event handlers simply call "Action" methods in the ViewModel class), but I have found no way to completely eliminate it.
Thanks for your help. Sorry again about the stupid questions.
WE ARE DYSLEXIC OF BORG. Refutance is systile. Your a$$ will be laminated.
There are 10 kinds of people in the world: People who know binary and people who don't.
|
|
|
|
|
Tom Delany wrote: Like for Button Click and other event handlers Most if not all of these can be handled by the VM, we use the MVVMLight framework and it does the job nicely, and once you have the pattern set it does not vary much.
Tom Delany wrote: I have been trying to keep what I do there to a bare minimum While this probably should be the goal of all of us I don't think it should be religious. I'm always pleased to move something into the VM but I'm not distressed if there is code behind.
I figure there must be a balance of ROI on time spent figuring out how to move something into the VM and getting the job done.
Never underestimate the power of human stupidity
RAH
|
|
|
|
|
Thanks. It's nice to see common sense applied when blogs, etc. that I have read on the subject sometimes almost take on religious zealotry.
WE ARE DYSLEXIC OF BORG. Refutance is systile. Your a$$ will be laminated.
There are 10 kinds of people in the world: People who know binary and people who don't.
|
|
|
|
|
Thanks Collin. Clear as mud.
Actually, I think I understand what you mean. A couple of things I feel a little fuzzy about, but I think I have enough info. to sort it out. If I run up against something I can't figure out, hopefully you won't mind if I bug you again.
WE ARE DYSLEXIC OF BORG. Refutance is systile. Your a$$ will be laminated.
There are 10 kinds of people in the world: People who know binary and people who don't.
|
|
|
|
|
|
Collin Jasnoch wrote: Place this DataTemplate in a resource dictionary and reference the dictionary in the UserControl that has the TabControl. It will then render the "OneOfYourViewModel" object as a "TheCorrespondingView" user control.
Create a ResourceDictionary under Application.Resources or in the MainWindows under Window.Resources, or does it really matter as long as it's closer to the root than where it is used?
Collin Jasnoch wrote: reference the dictionary in the UserControl that has the TabControl.
Will you show me a XAML example of what you mean?
Collin Jasnoch wrote: Another way is to define the DataTemplate with a key and then reference it for your "ItemTemplate".
I thought I had figured this way out, but then I stumbled because I have multiple DataTemplates and I was not sure if I still created a ResourceDictionary and gave it a key, and then bound that to the "ItemTemplate" of the TabControl, or if I had to assign a key to each template and somehow bind each one to ... something ?
Sorry. I'm a moron...
WE ARE DYSLEXIC OF BORG. Refutance is systile. Your a$$ will be laminated.
There are 10 kinds of people in the world: People who know binary and people who don't.
|
|
|
|
|
Tom Delany wrote: Create a ResourceDictionary under Application.Resources
Typically, you create an external ResourceDictionary file and then reference it in your App.Xaml (in the ResourceDictionary section). This would look something like this:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="AppResources.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
|
|
|
|
|
Thanks Pete. I'm still struggling with how to make the TabControl use the templates the way he suggested above.
I created the ITabItem interface, and the ObservableCollection of ITabItems as he suggested. I bound the TabControl ItemSource to the ITabItem ObservableCollection (which is the collection of ViewModels).
I figured out how to create a DataTemplate for each ViewModel as per Collin's suggestion. I think I could figure out how to bind one specific DataTemplate to the TabControl ItemTemplate, but I have multiple DataTemplates... Obviously I can't bind the Dictionary to the ItemTemplate.
Problem is, I can't even seem to come up with the right combination of words to Google for...
WE ARE DYSLEXIC OF BORG. Refutance is systile. Your a$$ will be laminated.
There are 10 kinds of people in the world: People who know binary and people who don't.
|
|
|
|
|
If you take a look at my article here[^], you should be able to see how I hooked up the DataTemplate elements to the TreeView for different ViewModels. Hopefully that should help.
|
|
|
|
|
Thanks Pete. I'll take a look at it. Sorry about the stupid questions.
After rereading the MSDN documentation about DataTemplates, and your suggestion about the ResourceDictionary (and removing the x:Key elements from my data templates ) I got it to actually sort of work. The DataTemplate documentation finally keyed me in on the fact that the way Collin was suggesting I do the templates using "DataType" would cause the DataTemplate to be "magically" applied for that type. That was what I was not seeing in my mind...
Now if I can just figure out how to make the tabs look like tabs again with headers at the top... Always something with WPF...
WE ARE DYSLEXIC OF BORG. Refutance is systile. Your a$$ will be laminated.
There are 10 kinds of people in the world: People who know binary and people who don't.
|
|
|
|
|
Tom - they aren't stupid questions, they are just questions about doing something differently. You have to remember that declarative programming is a lot different to the world of traditional coding; getting your head around it isn't easy, and a lot of very smart people have spent a lot of time figuring how to get this all to hang together. I've read articles by these smart people.
|
|
|
|