Bind control to another property - c#

My boss had downloaded a xaml control that I must use in app. It looks like ok but there is a strange trouble with inner logic - the
property CurrentColor (that I need to use in our app) is defined in control.xaml.cs file like :
public SolidColorBrush CurrentColor
{
get { return (SolidColorBrush)GetValue(CurrentColorProperty); }
set
{
SetValue(CurrentColorProperty, value);
ActiveColor = CurrentColor;
}
}
I am using this control in my dialog (that has its own view model class) and
I am writing this kind of binding:
CurrentColor="{Binding myOwnViewModel.ColorActualValue, Mode=Default, UpdateSourceTrigger=PropertyChanged}">
in myOwnViewModel.cs (that implements INotifyPropertyChanged) I have my property
public SolidColorBrush ColorActualValue{ // here is some logic}
But when I debug an app I have never target MY CurrentColor - I am always go to the CurrentColor from control.xaml.cs
How could I bind this "third party" control to my property from my ViewModel?
Perhaps this is because (control.xaml.cs):
public static DependencyProperty CurrentColorProperty =
DependencyProperty.Register("CurrentColor", typeof(SolidColorBrush), typeof(ColorPickerComboBox), new PropertyMetadata(Brushes.Chocolate));
public static RoutedEvent ActiveColorChangedEvent = EventManager.RegisterRoutedEvent("ActiveColorChanged",
RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ColorPickerComboBox));
I have found the question What's wrong with "DataContext = this" in WPF user controls? and removed DataContext = this; from constructor of this control - but this still not helped

Should the binding look like this?
CurrentColor="{Binding ColorActualValue, Mode=Default, UpdateSourceTrigger=PropertyChanged}">
The DataContext of your 'dialog' needs to be the ViewModel class that contains the ColorActualValue property
public Dialog()
{
DataContext = new myOwnViewModel();
}

Related

Binding A UserControl DependencyProperty, Always DefaultValue?

I've got a UserControl with a DependencyProperty created in its CodeBehind:
public partial class PanelMap_Control : UserControl
{
public ObservableCollection<GMapMarker> Markers
{
get { return (ObservableCollection<GMapMarker>)GetValue(MarkersProperty); }
set { SetValue(MarkersProperty, value); }
}
public static readonly DependencyProperty MarkersProperty = DependencyProperty.Register("Markers", typeof(ObservableCollection<GMapMarker>), typeof(PanelMap_Control), new PropertyMetadata(null));
}
Inside the UserControl is a Map, which contains the original collection of markers (not a DependencyProperty). I need to make this available for binding outside the UserControl, so at the end of the constructor (once the map's Markers are all setup), I set it to the control's DependencyProperty:
public PanelMap_Control()
{
InitializeComponent();
//...map setup...
this.Markers = _map.Markers;
}
Then, users of the UserControl can bind like:
<local:PanelMap_Control Markers="{Binding Path=MapMarkers, Mode=OneWayToSource}"/>
Where in the ViewModel:
public ObservableCollection<GMap.NET.WindowsPresentation.GMapMarker> MapMarkers
{
private get
{
return _mapMarkers;
}
set
{
_mapMarkers = value;
}
}
private ObservableCollection<GMap.NET.WindowsPresentation.GMapMarker> _mapMarkers;
The problem is, the ViewModel's MapMarkers property always ends up with the default value "null." I tried setting breakpoints on the SetValue call in PanelMap_Control and the ViewModel property's setter. The debugger first hits SetValue(), at which point _map.Markers is valid (non-null). THEN it hits the ViewModel's setter, with a value of null - and never reflects the actual valid object I pass to SetValue().
I'm sure I'm just missing something simple, but I can't for the life of me figure out why SetValue(non-null) would be followed by ViewModel.MapMarkers.set(null)...and never again.
(Side note 1: I realize this DependencyProperty won't work for TwoWay binding - i.e. I can't update _map.Markers in the UserControl. That's fine, I only need to read from it externally.)
(Side note 2: The _map.Markers object will never be changed - only the items in the collection - so setting the DependencyProperty to the initial collection should be sufficient.)
Please refer to the following questions.
OneWayToSource Binding seems broken in .NET 4.0
OneWayToSource binding resetting target value
OneWayToSource does actually reset the target property (Markers) initially. This is by design. There is more information about this on the links above.
As a workaround you could try to set up the binding programmatically:
public MainWindow()
{
InitializeComponent();
var vm = new ViewModel();
DataContext = vm;
vm.MapMarkers = control.Markers;
BindingOperations.SetBinding(control, PanelMap_Control.MarkersProperty, new Binding("MapMarkets") { TargetNullValue = control.Markers, FallbackValue = control.Markers });
}
XAML:
<local:PanelMap_Control x:Name="control" />

unable to use two way Binding with my control

I am new to binding. I have binded slider value to my control's property and my controls property get changed when I change the slider value.
Now, when I need to change the slider value by changing my property value, it does not work..
I modified the xaml from some internet source, but still not get the expected output.
can anyone help me out...
<Grid>
<cc:MyControl Name="mycntrl" ZoomPercentage="{Binding ElementName=slider,Path=Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></cc:MyControl>
<Slider Name="slider" Margin="20,20,20,400" Minimum="100" Maximum="400"></Slider>
</Grid>
Updated:
My code behind for my ZoomPercentage dependency property is below
public double ZoomPercentage
{
get
{
return (double)GetValue(ZoomPercentageProperty);
}
set
{
SetValue(ZoomPercentageProperty, value);
}
}
My dependency registration
public static readonly DependencyProperty ZoomPercentageProperty = DependencyProperty.Register("ZoomPercentage", typeof(double), typeof(MyControl), new FrameworkPropertyMetadata(ZoomPercentagePropertyChanged));
public static void ZoomPercentagePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
if (args.OldValue != null)
{
if ((double)args.NewValue != (double)args.OldValue)
{
MyControl mycontrol = obj as MyControl;
mycontrol .ZoomTo((int)((double)args.NewValue));
}
}
}
Your ZoomPercentage property should be implemented as a Dependencyproperty
Something like this
public class MyControl:UserControl
{
public MyControl() : base() { }
public double ZoomPercentage
{
get { return (double)this.GetValue(ZoomPercentageProperty); }
set { this.SetValue(ZoomPercentageProperty, value); }
}
public static readonly DependencyProperty ZoomPercentageProperty = DependencyProperty.Register(
"ZoomPercentage", typeof(double), typeof(MyControl:),new PropertyMetadata(0));
}
read more here
If you want a data bound control in the UI to update after changes made in code then you have to do one of two things. One option is to correctly implement the INotifyPropertyChanged interface in the class that you declared your Value property.
The other is to declare your Value property as a DependencyProperty, although you should only really do this in the code behind of your Window or UserControl and opt for the first method if you are using a view model. The purpose of these two methods is for you to 'plug in' to WPF notification framework, so that your UI control will update. Please read the linked pages for more information.

How to assign a property of type Control in XAML - error

I have a WPF user control with a property of type Control, to associate it with another control (usually a textbox) that it will send key presses to.
I can assign this property in XAML, and it compiles and works at runtime.
But the IDE shows an error "38 The method or operation is not implemented." on the TargetControl assignment.
<my:NumericButtonsControl
x:Name="NumericButtons"
TargetControl="{x:Reference Name=DataEntryTextBox}" />
The user control code in question looks like this:
public partial class NumericButtonsControl : UserControl
{
private Control _TargetControl;
public Control TargetControl
{
get
{
return _TargetControl;
}
set
{
_TargetControl = value;
}
}
}
When you write a WPF application, you'd probably want to avoid using x:Reference, as it's a feature of XAML 2009 which is only available for loose XAML.
Alternatively, you can use binding and its ElementName property. But for that to work you'll need to make TargetControl a dependency property. Then it will look like this:
C#
public Control TargetControl
{
get { return (Control)this.GetValue(TargetControlProperty); }
set { this.SetValue(TargetControlProperty, value); }
}
public static readonly DependencyProperty TargetControlProperty =
DependencyProperty.Register("TargetControl",
typeof(Control),
typeof(NumericButtonsControl),
new PropertyMetadata(null));
XAML:
<my:NumericButtonsControl
x:Name="NumericButtons"
TargetControl="{Binding ElementName=DataEntryTextBox}" />

DependencyProperties: PropertyChangedCallBack only called once

I created a control, derived from Canvas, that should plot a live diagram, given values that are passed via a binding to a DependencyProperty. The simplified version is this:
public class Plotter : Canvas
{
public float Value { get { return (float)GetValue(ValueProperty); } set { SetValue(ValueProperty, value); } }
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(float), typeof(Plotter),
new PropertyMetadata(0f, new PropertyChangedCallback(ValueChangedCallBack)));
public static void ValueChangedCallBack(DependencyObject property, DependencyPropertyChangedEventArgs args)
{
Plotter plotter = (Plotter)property;
plotter.Value = (float)args.NewValue; //<-- Removed this line to get it to work
// Actually draw the value into the canvas geometry
plotter.PlotValue(plotter.Value);
}
}
I bound the control like this:
<mystuff:Plotter Value="{Binding MyViewModelProperty}" Height="50" Width="200" />
My ViewModel implements INotifyPropertyChanged and calls PropertyChanged correctly. If I bind MyViewModelProperty to a textbox, it correctly updates every time. Only if I bind it to my own control, my ValueChangedCallBack is only called once as the page is loaded, and then never again.
What am I not seeing here? Thanks for any help!
Solved: I dont have to set the Value explicitly in the callback.
You set the property Value on the callback for the property Value changing. That doesn't make much sense in any case. But is that locally set value overriding the binding value, causing your binding to no longer be set on the dependency property?
Do you need to set the Mode of your binding to TwoWay?
Should you not be using DependencyProperty.Register instead of DependencyProperty.RegisterAttached?

Binding Dependency Properties

So here I come creating a user control. It consists of a treeview dropping down from a combobox.
Actually, there is a button with a control (DropTree) dropping down from its contextmenu. So I have a control DropTree.
public partial class DropTree : UserControl
{
public TreeView TreeView
{ get{return treeView;} }
public DropTree()
{ InitializeComponent(); }
}
to simplify it, I made the TreeView control public, then I have my main control which is called ComboTreeView.
Now I need to represent some treeview properties in it, so I define several dependency properties:
public static DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", typeof(object), typeof(ComboTreeView), new FrameworkPropertyMetadata { Inherits = true, IsNotDataBindable = false, DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged });
public object SelectedItem
{
get { return GetValue(SelectedItemProperty); }
set { SetValue(SelectedItemProperty, value); }
}
and in constructor it is:
public ComboTreeView()
{
InitializeComponent();
TreeViewControl.SetBinding(TreeView.SelectedItemProperty, new Binding("SelectedItem") { Source = this, Mode = BindingMode.TwoWay });
}
and it all seems ok, until i run it. It crashes saying that SelectedItem cannot be binded to data. I don't understand?
The same goes for ItemsSource and SelectedValue... but only SelectedValuePath property defined this way goes fine.
Can anybody help? Or is there any other way to bind it correctly?
PS: by the way, I need to use DataBinding for ComboTreeView in my code later.
Try to set the Binding on SelectedValue instead of SelectedItem.
TreeView.SelectedItem is a readonly property. You can't set it, whether explicitly or through binding. In order to select a node in a TreeView, you must set the TreeViewItem.IsSelected property to true.

Categories