Multiple sources bound to same target dependency property - c#

Is it possible to attach multiple (two-way) source bindings to a dependency property? That is, so that if one source changes, the DP gets updated via one binding, and the change would then get propagated to the second source via the second binding.
In my scenario, the dependency property is in a user control, the first binding is to its internal view-model, and the second binding is for the view-model of the consumer of the user control.
Below is for illustration. The consumer of the user control looks like this:
<MyControl SelectedValue="{Binding Selected,Mode=TwoWay}" />
Now "MyControl" has the "SelectedValue" defined as a dependency property. The XAML for the control binds to its dependency property like this:
<UserControl>
<Grid x:Name="LayoutRoot">
<TextBox Text="{Binding SelectedValue,Mode=TwoWay,
RelativeSource={RelativeSource AncestorType=UserControl}}"
/>
</Grid>
</UserControl>
"MyControl" has its internal data context set, in the control's constructor, to its own view model:
LayoutRoot.DataContext = new ViewModelForControl();
So far so good, but if I then attempt to add the second binding, that being the dependency property to a "SelectedInternal" property on the internal view-model --
SetBinding(SelectedValueProperty, new Binding("SelectedInternal") {
Source = LayoutRoot.DataContext,
Mode = BindingMode.TwoWay
});
-- then the first binding is destroyed. Is there a way to add this second binding while preserving the first?

Is this being overthought?
Why not simply do the plumbing in the code behind of the custom control and forgo binding?
This can be done by
SelectedValue dependency property will utilize its changed handler and upon any change set SelectedInternal to the new value.
When SelectedInternal changes write to the property SelectedValue.
You create the VM on the control, so you have access to the VM and its property, which can provide the vectoring of the data for two way transfer.
At the end of the day binding is just getting a reference via reflection. In this case how one gets a reference is immaterial to simply writing back and forth between two properties.
Or am I missing something?

Related

How to bind mdiContainer children to viewModel property?

I am using CodePlex wpfmdi container for my WPF application.
I need to bind MdiContainer's children to a viewModel property.
<mdi:MdiContainer Name="Container" Grid.Row="1" Background="GhostWhite" Children="{Binding Path=Container}"/>
If I do this I am getting this error:
Object of type 'System.Windows.Data.Binding' cannot be converted to type 'System.Collections.ObjectModel.ObservableCollection`1[WPF.MDI.MdiChild]'
This is what the Children property in MdiContainer looks like:
public ObservableCollection<MdiChild> Children { get; set; }
What am I doing wrong?
The Children property is not exposed as a dependency property, which means you cannot bind it. Furthermore, it is initialized once in the constructor of the MdiContainer type and then a handler is added to the CollectionChanged event of the underlying ObservableCollection<MdiChild>. It is never updated or removed.
Therefore, although the Children property has a setter, it will break the control if you use it to set a different collection. This also implies that you cannot simply create attached properties to expose a bindable Children dependency property.
Apart from that, MdiChild is a Control, so it actually contradicts the purpose of your view model. If you expose a collection of user interface controls from your view model this conflicts with the MVVM pattern. View models should not have any knowledge about the view. However, the MDI controls do not seem to follow the usual WPF practices for custom controls, so there is not much room for improvement here, data templating is not supported, the MdiContainer is a UserControl and there are very limited dependency properties.
If you really want to continue working with this control with your current approach, you could:
Create a custom attached behavior to synchronize your view model collection with the Children collection of the MdiContainer and vice-versa, see XAML behaviors in WPF.
Use the Loaded event to assign the Children collection to your view model property.
<mdi:MdiContainer Name="Container" Grid.Row="1" Background="GhostWhite" Loaded="MdiContainer_OnLoaded">
private void MdiContainer_OnLoaded(object sender, RoutedEventArgs e)
{
var mdiContainer = (MdiContainer)sender;
var dataContext = (Main)mdiContainer.DataContext;
if (dataContext == null)
return;
dataContext.Children = mdiContainer.Children;
}
Use an EventTrigger on the Loaded event with a custom trigger action that sets the Children collection. This is just a different variant of the previous approach that does not require code-behind.
The new XAML behaviors for WPF package, which replaces the legacy Blend behaviors from the System.Windows.Interactivity namespace already includes such a trigger action. Install the Microsoft.Xaml.Behaviors.Wpf NuGet package and use this:
<mdi:MdiContainer Name="Container" Grid.Row="1" Background="GhostWhite">
<behaviors:Interaction.Triggers>
<behaviors:EventTrigger EventName="Loaded">
<behaviors:ChangePropertyAction TargetObject="{Binding DataContext, ElementName=Container}"
PropertyName="Children"
Value="{Binding Children, ElementName=Container}"/>
</behaviors:EventTrigger>
</behaviors:Interaction.Triggers>
</mdi:MdiContainer>
Note that with these approaches, you either synchronize to your own collection or you work directly with the collection of the MdiContainer that you passed to your view model. These are only workarounds. If you would want to implement this in a clean and MVVM compliant way, I think you would need to extend or fix the control itself, which is rather costly and not recommendable, since it seems to be dead anyway.

Custom XAML Binding SOURCE Class

I am trying to find a better way to declare the ViewModel a UWP XAML Page uses.
At this moment,
I declare a ViewModel class ViewModelClass that contains my data properties.
Then I declare an instance of that class as StaticResource of the Page. I like calling those VIEW for consistency across all my Page designs.
Finally, I declare the Page's DataContext as a Binding to the StaticResource VIEW.
This yields a page that understands what data structure is in use and allows AutoComplete when working Bindings. Nice, though lots of lines of same-old-same-old code.
Only, it is not really suitable to ViewModels as the declared resource is a static resource. It is instantiated when the page is instantiated. Most pages will receive a ViewModel parameter upon NavigatedTo, which cannot be used to replace the static resource, because it is, well. static.
So I end up changing the Page's DataContext upon navigation from the initial reference to VIEW to the ViewModel instance I actually want to use.
Big caveat is to declare the back-reference to the page's DataContext when deep in the bowels of a Master-Detail situation is rather horrible. Imagine a collection whose display is in part depending on a Master's property.
How do you tie back robustly to the DataContext of the page from anywhere inside the page?
I have tried giving the page a Name (PAGE for simplicity) and then using ElementName=PAGE, Path=DataContext.someProperty. Ugly, plus you lose all information of the class represented by DataContext.
Another approach is to create a Wrapper around the actual ViewModel called StaticViewModel that has only one property: public ViewModel viewModel. Now I can declare the wrapper as a StaticResource, and tell the page's top-level FrameworkElement to use VIEW.viewModel as its DataContext. Works, and reliably, but sooooo ackward and cumbersome.
I would LOVE to implement a SOURCE class for bindings called PageDataContext that would do nothing else but to loop into the page and get the DataContext from there.
Imagine: {Binding someProperty, Source={PageDataContext}
How would I go about declaring said Source class for a UWP app???
I would LOVE to implement a SOURCE class for bindings called PageDataContext that would do nothing else but to loop into the page and get the DataContext from there. Imagine: {Binding someProperty, Source={PageDataContext}
For your requriment, you could implement your viewmodel in the page Resources and give it x:key. When you bind the property of viewmodel you could access this viewmodel with x:key Source={StaticResource ViewModel} for more please refer the following code.
ViewModel
public class ViewModel
{
public ViewModel()
{
Visibility = false;
}
public bool Visibility { get; set; }
}
Xaml
<Page.Resources>
<local:ViewModel x:Key="ViewModel" />
</Page.Resources>
<TextBlock
Width="100"
Height="44"
Text="{x:Bind Name}"
Visibility="{Binding Visibility, Source={StaticResource ViewModel}}" />
Well, no dice so far.
Working with all those options I found that the best one is a Wrapper class that can be assigned to a static resource which in turn is the basis for the page's DataContext. The wrapped instance of the actual ViewModel is then assigned during OnNavigatedTo() and used as the DataContext of the basic FrameworkElement of the page.
Brr, so much verbose code.
STILL WONDERING how to implement a different version of a source directive. Is there no way to declare one's own Source for a Data Binding? Is this stuff really hard-coded into the framework???

Assigning view model to data context: when does view model override XAML element?

I'm learning WPF and MVVM. I'm curious about what happens in a particular situation.
Assuming that my view model implements INotifyPropertyChanged, the situation is where my code has already constructed my view model and then assigns it to my window's DataContext.
At the point in time that I assign the view model to DataContext, the value in my view model may be different than the value in the XAML element. And so I'm curious about which value wins.
I assumed the XAML element would pull in all the values from my view model but that is not what seems to be happening. Changes made to my view model correctly notify and update the XAML elements. But those changes made before I set DataContext are not reflected in the XAML elements.
Can anyone confirm my interpretation is correct? I've Googled extensively but could not find anything on this specific issue. Yet that seems to be the behavior in my application. Would appreciate someone else perspective or a link to a more detailed discussion.
I'm curious about the situation where my view model implements INotifyPropertyChanged, my code builds my view model and then assign it to my windows DataContext.
The problem is, at that stage where I assign to DataContext, the value in the XAML element may not match my view model. So which one wins.
Based on my testing, it appears that the value already in the XAML element wins. And if I want it set to the value in my view model, I must set it somehow or have my view model send a new property-changed notification.
Sounds like your changing your data template to show a hardcoded value rather than the default value provided by the binding.
For example in a TextBlock you can only assign the Text property once, either via a binding syntax where the value is sourced from the DataContext, or a static value.
<TextBlock Text="{Binding Path=Display}"/> <- only uses the DataContext
<TextBlock Text="123"/> <- only shows the static value
If you try and set the Text property twice, you get an error:
<TextBlock Text="{Binding Path=Display}">
<TextBlock.Text>
123
</TextBlock.Text>
</TextBlock>
You can provide the binding with a fallback value when there is no valid value available via the DataContext such as an exception being thrown, but the DataContext value wins when it provides a value:
<TextBlock Text="{Binding Path=Display, FallbackValue=123}" />
If you want to set a default value, you might be best to set a default in the constructor of the DataContext class and leave the binding in the Xaml to only source from the DataContext

To use (DataContext) or not to use

I've got a dilemma regarding the DataContext. Let's inspect the following piece of XAML:
<Window xmlns:my="clr-namespace:MyNamespace.Controls"
... >
...
<my:MyControl Name="{Binding Prop1}" Value="{Binding Prop2}" />
</Window>
Obviously, the Window's code-behind contains something like:
DataContext = someViewModel;
Author's intentions are clear - he wants to bind MyControl's Name and Value to Window's DataContext's Prop1 and Prop2. And this will of course work. Unless. (dramatic pause)
Unless MyControl is a composite UserControl, which also wants to take advantage of short notation of bindings and sets its DataContext to its own viewmodel. Because then it will become clear, that the bindings in Window's XAML actually bind to MyControl's DataContext (previously inherited from Window's one) and now they will stop working (or worse, will keep working if MyControl's viewmodel actually contains properties named Prop1 and Prop21).
In this particular case solution is to bind in Window's code explicitly:
<Window x:Name="rootControl"
xmlns:my="clr-namespace:MyNamespace.Controls"
... >
...
<my:MyControl Name="{Binding ElementName=rootControl, Path=DataContext.Prop1}"
Value="{Binding ElementName=rootControl, Path=DataContext.Prop2}" />
</Window>
TL;DR If we're using short notation of bindings (when binding to DataContext) we may encounter quite tough to nail bugs resulting from bindings suddenly pointing to wrong DataContext.
My question is: how to use short binding notation without risk, that I'll bind to wrong DataContext? Of course I may use the short notation when I'm sure, that I'll be using inherited DataContext and long notation when I'm sure, that control will modify its DataContext. But that "I'm sure" will work only until first mistake, which will consume another hour of debugging.
Maybe I'm not following some MVVM rule? E.g. for example DataContext should be set only once on the top level and all composited controls should bind to something else?
1 I've gone through that, actually. The Window's DataContext contained a property named (say) Prop and the control replaced its DataContext with a class, which also contained a property Prop and everything worked fine. Problem appeared when I tried to use (unconsciously) the same pattern with non-matching property names.
By request:
Fragment of MyControl's code:
public string Name
{
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
// Using a DependencyProperty as the backing store for Name. This enables animation, styling, binding, etc...
public static readonly DependencyProperty NameProperty =
DependencyProperty.Register("Name", typeof(string), typeof(MyControl), new PropertyMetadata(null));
public int Value
{
get { return (int)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(int), typeof(MyControl), new PropertyMetadata(0));
Window's viewmodel:
public class WindowViewmodel : INotifyPropertyChanged
{
// (...)
public string Prop1
{
get
{
return prop1;
}
set
{
prop1 = value;
OnPropertyChanged("Prop1");
}
}
public int Prop2
{
get
{
return prop2;
}
set
{
prop2 = value;
OnPropertyChanged("Prop2");
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
Now assume, that on changing of Name and Value dependency properties, MyControl generates some viewmodel and executes the code:
model = new MyControlViewModel(Name, Value);
this.DataContext = model;
And internal MyControl controls bind to this DataContext.
From now on, the original Name and Value bindings will no longer work.
Unless MyControl is a composite UserControl, which also wants to take advantage of short notation of bindings and sets its DataContext to its own viewmodel.
And that's where I stopped reading. This is, imho, a MVVM anti-pattern.
The reason for this is twofold. First, you screw with anybody who is using the control. "Hey," you say, "you can't bind your stinky VM to my beautiful UI. You have to use MY custom VM!" But what if your VM is hard to use, lacks logic or features needed by the overall application? What happens when, to use your UI, we have to translate our VM/models back and forth with your VM? Pain in the butt.
Second is that your custom control is UI. Its logic is UI logic, and so it is unnecessary to use a view model. It is better to expose DependencyProperties on your control and update your UI as necessary. That way anybody can bind to your UI and use it with any model or view model.
You can solve your problems by simply not using what you call a 'composite control. While I understand that you want to encapsulate some functionality in the associated view model, you don't need to set the view model to the UserControl.DataContext internally.
What I mean by this is that you can have a view model for any or all of your UserControls, but they're data classes, not UI classes, so keep them out of the view code. If you use this method of adding DataTemplates into Resources, then you won't need to set any DataContext properties at all:
<DataTemplate DataType="{x:Type ViewModels:YourUserControlViewModel}">
<Views:YourUserControl />
</DataTemplate>
The final difference is that you should add your view model for your UserControls as properties in a parent view model. This way, you still have no duplicated code (except maybe just a property declaration) and more importantly, you have no Binding problems from mixing DataContext values.
UPDATE >>>
When using this DataTemplate method of hooking up views and view models, you can display your view by Binding your view model property to the Content property of a ContentControl like this:
<ContentControl Content="{Binding YourViewModelProperty}" />
At run time, this ContentControl will be rendered as whatever view or UserControl that you defined in the DataTemplate of the relevant type for that property. Note that you shouldn't set the x:Key of the DataTemplate, otherwise you'd also need to set the ContentControl.ContentTemplate property and that can limit the possibilities afforded by this method.
For example, without setting the x:Key property on your DataTemplates, you could have a property of a base type and by setting it to different sub class, you can have different views for each from the one ContentControl. That is the basis of all of my views... I have one property of a base class view model data bound like this example and to change views, I just change the property to a new view model that is derived from the base class.
UPDATE 2 >>>
Here's the thing... you shouldn't have any 'proxy' object in your UserControls doing anything... it should all be done through properties. So just declare a DependencyProperty of the type of that object and supply it from the view model through data Binding. Doing it this way means that it will be easy to test the functionality of that class, whereas testing code behind views is not.
And finally, yes, it's perfectly fine doing this in MVVM:
<Controls:SomeUserControl DataContext="{Binding SomeViewModelProperty}" />
The overriding goal of MVVM is just to provide separation between the UI code and the view model code, so that we can easily test what's in the view models. That is why we try to remove as much functionality code from the views as possible.
within a usercontrol you should never set the datacontext to "this" or a new viewmodel. a developer/user of your MyUsercontrol expect that the datacontext inherit from top to bottom (from mainwindow to your myusercontrol).
your usercontrol xaml should use element binding
MyUserControl.xaml
<UserControl x:Name="uc">
<TextBlock Text="{Binding ElementName=uc, Path=Name}"/>
<TextBlock Text="{Binding ElementName=uc, Path=Value}"/>
this means your following code will work now in every situation
<Window xmlns:my="clr-namespace:MyNamespace.Controls">
<my:MyControl Name="{Binding Prop1}" Value="{Binding Prop2}" />
</Window>
the property Prop1 from Datacontext mainwindow is bound to the DP Name from your MyUsercontrol and the Textblock.Text within your MyUsercontrol is bound to the DP Name.
I've never met such a problem. It seems to be a little bit theoretical to me but maybe because of my approach to working with DataContext in WPF.
I minimize the explicit use DataContext property. I set it manually only for windows.
I have one dedicated method which is responsible for displaying new windows and it is the only one place where the DataContext property is set explicitly.
DataContext property for Windows is set to root ViewModel which contains child ViewModels, which contain...
I allow WPF to select which View should be used to display given a ViewModel by using DataTemplate
In my application I have a single ResourceDictionary which contains mappings between all ViewModels and Views.

Why does binding to a DepenencyProperty on a user control use the user control's Data Context?

Say I have a WPF application (exe) that has this in the MainWindow.xaml:
<Grid>
<extraControls:MyMVVMUserControl MyDependencyProperty="{Binding Something}"/>
<extraControls:MyUserControl MyDependencyProperty="{Binding Something}" />
</Grid>
and my MainWindow.xaml.cs looks like this:
public MainWindow()
{
DataContext = new MainWindowVM();
InitializeComponent();
}
And my MainWindowVM.cs has a property setup for Something that notifies on property changed.
The user controls are made in a separate dll. As you may guess, MyMVVMUserControl has the DataContext set to a view model.
public MyMVVMUserControl()
{
DataContext = new MyMVVMUserControlVM();
InitializeComponent();
}
MyUserControl does not have a DataContext set in the code behind.
So the interesting thing is that they both have MyDependencyProperty setup exactly the same.
But the MVVM version does not work.
After digging in a bit, I found that the {Binding Something} in MainWindow.xaml is using the View Model setup for the MyMVVMUserControl as the DataContext (rather than the DataContext set in MainWindow.cs (set to MainWindowVM)).
And my question is why?
Why would WPF look inside the user control and use it's DataContext for a binding that is in the actual application?
(NOTE: I know I can get around this by setting the source in the binding, but I want others to be able to use my user controls. But with this issue, I now have a built-in "gotcha" for anyone I want to use my user controls.)
I think I understand you problem, and I'm gonna to give a solution that works for me (I had this problem before). The think is that seams that you are setting the DataContext for you MyMVVMUserControl in code behind, and then it take the bindings from that.
The solution I found for this, is to set the datacontext in code behind, but not at the user control. Set the datacontext for the UserControl's child item. For instance, supose this is the Xaml of your UserControl:
<UserControl ... x:Name="userControl">
<Grid x:Name="rootContainer">
...
</Grid>
</UserControl>
Then in the code behind set the rootContainer's data context, in this way all visual children can access to the control data context, and also the user control datacontext is empty.
...
rootContainer.DataContext = new UserControlViewModel();
...
Hope this may helps you to solve your issues...
You really shouldn't ever set the DataContext of a UserControl from inside the UserControl. By doing so, you are preventing any other DataContext from getting passed to the UserControl, which defeats one of WPF's biggest advantages of having separate UI and data layers.
WPF objects only inherit their DataContext from the parent object if the DataContext is not set to anything else. When your MyMVVMUserControl is being created, you are setting the DataContext to a new MyMVVMUserControlVM, which prevents the DataContext from being inherited from MainWindow.
So its normal that your MVVMUserControl would have it's DataContext set to your MyMVVMUserControlVM, because you set it explicitly in the UserControl's constructor.
This is by-design. UI objects in WPF/MVVM are only meant to be visual representations of the data layer, so it wouldn't make much sense to set the data layer and then try to bind your properties to something that is not on the data layer.
For example, take this line of code:
<UserControl DataContext="{Binding ClassA}" Content="{Binding Name}" />
This would bind the Content property to UserControl.DataContext.Name, which is ClassA.Name. It wouldn't make much sense if this would result in binding to UserControl.Parent.DataContext.Name, as the binding should refer to to the current object's DataContext, and not the Parent's DataContext.
So the only time I ever set the DataContext of a UserControl from inside the UserControl itself is if the UserControl is its own separate object that is never meant to interact with data from the rest of the application. Which so far has been never :)
Typically my UserControls are almost always one of two things:
Either a visual representation of a ViewModel (or Model), such as a CustomerUserControl for a CustomerViewModel, in which case I pass them the DataContext they need when they get used
For example,
<local:CustomerUserControl DataContext="{Binding SelectedCustomer}" />
or
<DataTemplate DataType="{x:Type local:CustomerModel}">
<local:CustomerUserControl />
</DataTemplate>
Or a self-sustained UI object that receives any external data it needs via custom DependencyProperties, and does any additional logic in the code-behind the control, such as a DatePicker control that has a SelectedDate dependency property, or a CalculatorUserControl with dependency properties for Equation and Value
<local:DatePickerUserControl SelectedDate="{Binding SomeDate}" />
<local:CalculatorUserControl Equation="{Binding SomeString}"
Value="{Binding SomeDouble}" />
In your case, it sounds like you should be using the first case, and should be passing a ViewModel into your UserControl containing the data it needs.
<extraControls:MyMVVMUserControl DataContext="{Binding MyMVVMUserControlVM}"
MyDependencyProperty="{Binding Something}">
or
<extraControls:MyMVVMUserControl MyDependencyProperty="{Binding Something}">
<extraControls:MyMVVMUserControl.DataContext>
<viewModels:MyMVVMUserControlVM />
</extraControls:MyMVVMUserControl.DataContext>
<extraControls:MyMVVMUserControl />

Categories

Resources