WPF MenuItem.IsChecked binding not working [duplicate] - c#

This question already has answers here:
DependencyProperty not triggered
(2 answers)
DependencyProperty getter/setter not being called
(2 answers)
Why are .NET property wrappers bypassed at runtime when setting dependency properties in XAML?
(1 answer)
Closed 5 years ago.
I have a simple menu and would like the IsChecked property of the MenuItems to be bound so that I could later manipulate them in code behind. I have a break point set in the getter and setter of the property but they are never hit.
I've searched other questions and none have shed any light on my issue. I created a skeleton project to demonstrate what I'm seeing.
MainWindow.xaml:
<Window x:Class="POC_BindingMenuItemIsChecked.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:POC_BindingMenuItemIsChecked"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:MainWindowViewModel x:Key="mainWindowViewModel"/>
</Window.Resources>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="Choice">
<MenuItem Header="Alpha"
IsCheckable="True"
Checked="MenuItemAlpha_Checked"
IsChecked="{Binding AlphaIsRecording, Mode=TwoWay}"/>
<MenuItem Header="Bravo"
IsCheckable="True"
Checked="MenuItemBravo_Checked"
IsChecked="{Binding
Source={StaticResource mainWindowViewModel},
Path=BravoIsRecording,
Mode=TwoWay}"/>
<MenuItem Header="Charlie"
IsCheckable="True"
Checked="MenuItemCharlie_Checked"
IsChecked="{Binding CharlieIsRecording, Mode=TwoWay}"/>
</MenuItem>
</Menu>
</DockPanel>
</Window>
MainWindow.xaml.cs:
public partial class MainWindow : Window
{
private MainWindowViewModel _MainWindowViewModel = null;
public MainWindow()
{
InitializeComponent();
// get a reference to the binding sources so we can set the properties
_MainWindowViewModel = new MainWindowViewModel();
this.DataContext = _MainWindowViewModel;
}
private void MenuItemAlpha_Checked(object sender, RoutedEventArgs e)
{
//no-op yet
}
private void MenuItemBravo_Checked(object sender, RoutedEventArgs e)
{
//no-op yet
}
private void MenuItemCharlie_Checked(object sender, RoutedEventArgs e)
{
//no-op yet
}
}
MainWindowViewModel.cs:
class MainWindowViewModel : DependencyObject
{
// Alpha
public static PropertyMetadata AlphaIsRecordingPropertyMetadata
= new PropertyMetadata(null);
public static DependencyProperty AlphaIsRecordingProperty
= DependencyProperty.Register(
"AlphaIsRecording",
typeof(bool),
typeof(MainWindowViewModel),
AlphaIsRecordingPropertyMetadata);
public bool AlphaIsRecording
{
get { return (bool)GetValue(AlphaIsRecordingProperty); }
set { SetValue(AlphaIsRecordingProperty, value); }
}
// Bravo
public static PropertyMetadata BravoIsRecordingPropertyMetadata
= new PropertyMetadata(null);
public static DependencyProperty BravoIsRecordingProperty
= DependencyProperty.Register(
"BravoIsRecording",
typeof(bool),
typeof(MainWindowViewModel),
BravoIsRecordingPropertyMetadata);
public bool BravoIsRecording
{
get { return (bool)GetValue(BravoIsRecordingProperty); }
set { SetValue(BravoIsRecordingProperty, value); }
}
// Charlie
public static PropertyMetadata CharlieIsRecordingPropertyMetadata
= new PropertyMetadata(null);
public static DependencyProperty CharlieIsRecordingProperty
= DependencyProperty.Register(
"CharlieIsRecording",
typeof(bool),
typeof(MainWindowViewModel),
CharlieIsRecordingPropertyMetadata);
public bool CharlieIsRecording
{
get { return (bool)GetValue(CharlieIsRecordingProperty); }
set { SetValue(CharlieIsRecordingProperty, value); }
}
}
EDIT:
Because of the solution that mm8 provided (POCO and not Dependency) I've modified the solution. It now functions as a set of three MenuItems that behave as radio buttons. The code follows:
MainWindow.xaml:
<Window x:Class="POC_BindingMenuItemIsChecked.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:POC_BindingMenuItemIsChecked"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:MainWindowViewModel x:Key="mainWindowViewModel"/>
</Window.Resources>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="Choice">
<MenuItem Header="Alpha"
IsCheckable="True"
Checked="MenuItemAlpha_Checked"
IsChecked="{Binding AlphaIsRecording, Mode=TwoWay}"/>
<MenuItem Header="Bravo"
IsCheckable="True"
Checked="MenuItemBravo_Checked"
IsChecked="{Binding BravoIsRecording, Mode=TwoWay}"/>
<MenuItem Header="Charlie"
IsCheckable="True"
Checked="MenuItemCharlie_Checked"
IsChecked="{Binding CharlieIsRecording, Mode=TwoWay}"/>
</MenuItem>
</Menu>
</DockPanel>
</Window>
MainWindow.xaml.cs:
public partial class MainWindow : Window
{
private MainWindowViewModel _mainWindowViewModel = null;
public MainWindow()
{
InitializeComponent();
// get a reference to the binding sources so we can set the properties
_mainWindowViewModel = new MainWindowViewModel();
this.DataContext = _mainWindowViewModel;
}
private void MenuItemAlpha_Checked(object sender, RoutedEventArgs e)
{
_mainWindowViewModel.BravoIsRecording = false;
_mainWindowViewModel.CharlieIsRecording = false;
}
private void MenuItemBravo_Checked(object sender, RoutedEventArgs e)
{
_mainWindowViewModel.AlphaIsRecording = false;
_mainWindowViewModel.CharlieIsRecording = false;
}
private void MenuItemCharlie_Checked(object sender, RoutedEventArgs e)
{
_mainWindowViewModel.AlphaIsRecording = false;
_mainWindowViewModel.BravoIsRecording = false;
}
}
ViewModelBase.cs:
class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
// Create the OnPropertyChanged method to raise the event
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
MainWindowViewModel.cs:
class MainWindowViewModel : ViewModelBase
{
private bool _alphaIsRecording = false;
private bool _bravoIsRecording = false;
private bool _charlieIsRecording = false;
// Alpha
public bool AlphaIsRecording
{
get { return _alphaIsRecording; }
set
{
_alphaIsRecording = value;
OnPropertyChanged("AlphaIsRecording");
}
}
// Bravo
public bool BravoIsRecording
{
get { return _bravoIsRecording; }
set
{
_bravoIsRecording = value;
OnPropertyChanged("BravoIsRecording");
}
}
// Charlie
public bool CharlieIsRecording
{
get { return _charlieIsRecording; }
set
{
_charlieIsRecording = value;
OnPropertyChanged("CharlieIsRecording");
}
}
}

You are binding to AlphaIsChecked and BravoIsChecked but I don't see any such properties? Try to bind to BravoIsRecording:
<MenuItem Header="Bravo"
IsCheckable="True"
Checked="MenuItemBravo_Checked"
IsChecked="{Binding
Source={StaticResource mainWindowViewModel},
Path=BravoIsRecording,
Mode=TwoWay}"/>
Also, a view model doesn't typically inherit from DependencyObject and define dependency properties. Turn your properties into ordinary CLR properties and put a breakpoint in the setter of the BravoIsRecording and it should get hit when you check the CheckBox.

Related

WPF usercontrol Twoway binding Dependency Property

I created a Dependency Property in the usercontrol, but however changes in the usercontrol was NOT notified to the Viewmodel
Usercontrol
<UserControl x:Class="DPsample.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<TextBox x:Name="txtName"></TextBox>
</Grid>
UserControl.cs
/// <summary>
/// Interaction logic for UserControl1.xaml
/// </summary>
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
#region SampleProperty
public static readonly DependencyProperty SamplePropertyProperty
= DependencyProperty.Register("SampleProperty",
typeof(string),
typeof(UserControl1),
new PropertyMetadata(OnSamplePropertyChanged));
public string SampleProperty
{
get { return (string)GetValue(SamplePropertyProperty); }
set { SetValue(SamplePropertyProperty, value); }
}
static void OnSamplePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
(obj as UserControl1).OnSamplePropertyChanged(e);
}
private void OnSamplePropertyChanged(DependencyPropertyChangedEventArgs e)
{
string SamplePropertyNewValue = (string)e.NewValue;
txtName.Text = SamplePropertyNewValue;
}
#endregion
}
MainWindow
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DPsample" x:Class="DPsample.MainWindow"
Title="MainWindow" Height="350" Width="525">
<Grid>
<local:UserControl1 SampleProperty="{Binding SampleText,Mode=TwoWay}" HorizontalAlignment="Left" Margin="76,89,0,0" VerticalAlignment="Top" Width="99"/>
<Button Content="Show" HorizontalAlignment="Left" Margin="76,125,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
</Grid>
MainWindow.cs
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainViewModel();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var item = this.DataContext as MainViewModel;
MessageBox.Show(item.SampleText.ToString());
}
MainViewModel.cs
public class MainViewModel : NotifyViewModelBase
{
public MainViewModel()
{
this.SampleText = "test";
}
private string _sampleText;
public string SampleText
{
get { return _sampleText; }
set { _sampleText = value; OnPropertyChanged("SampleText"); }
}
}
Bind the TextBox.Text property in the UserControl to its SampleProperty like this:
<TextBox Text="{Binding SampleProperty,
RelativeSource={RelativeSource AncestorType=UserControl}}"/>
Now you could simply remove your OnSamplePropertyChanged callback.
You might also register SampleProperty to bind two-way by default like this:
public static readonly DependencyProperty
SamplePropertyProperty = DependencyProperty.Register(
"SampleProperty", typeof(string), typeof(UserControl1),
new FrameworkPropertyMetadata(
null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
An alternative way to do this is an ElementName Binding. First assign the x:Name attribute to the UserControl (for example x:Name="MyUC"), then change the binding to:
<TextBox Text="{Binding ElementName=MyUC, Path=SampleProperty}"/>

Can't get bound value when setting DataContext in Loaded event

I have a user control that shows a bindable text. If I put this user control in a window and set the DataContext in Loaded event of that window, I can't retrieve the text in the Loaded event of the control. Why?
If I set the DataContext in MainWindow constructor everything works.
So is it wrong to set the DataContext in Loaded event?
Here is my sample code:
<UserControl x:Class="UserControlBinding.TestControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
x:Name="thisControl"
Loaded="OnLoaded"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<TextBlock Text="{Binding TextToShow, ElementName=thisControl}" />
</Grid>
public partial class TestControl : UserControl
{
public string TextToShow
{
get { return (string)GetValue(TextToShowProperty); }
set { SetValue(TextToShowProperty, value); }
}
public static readonly DependencyProperty TextToShowProperty =
DependencyProperty.Register("TextToShow", typeof(string), typeof(TestControl), new PropertyMetadata(null));
public TestControl()
{
InitializeComponent();
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
Debug.WriteLine("TestControl.OnLoaded: DataContext=" + DataContext);
Debug.WriteLine("TestControl.OnLoaded: TextToShow=" + TextToShow);
}
}
<Window x:Class="UserControlBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:UserControlBinding"
Loaded="OnLoaded"
Title="MainWindow" Height="350" Width="525">
<Grid>
<local:TestControl TextToShow="{Binding TextToBind}" />
</Grid>
public partial class MainWindow : Window
{
public string TextToBind
{
get { return (string)GetValue(TextToBindProperty); }
set { SetValue(TextToBindProperty, value); }
}
public static readonly DependencyProperty TextToBindProperty =
DependencyProperty.Register("TextToBind", typeof(string), typeof(MainWindow), new PropertyMetadata(null));
public MainWindow()
{
InitializeComponent();
//this.DataContext = this; // if I do this it works
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
Debug.WriteLine("+MainWindow.OnLoaded");
TextToBind = "this is the text to bind";
this.DataContext = this;
Debug.WriteLine("-MainWindow.OnLoaded");
}
}
Debug output is:
+MainWindow.OnLoaded
-MainWindow.OnLoaded
TestControl.OnLoaded: DataContext=UserControlBinding.MainWindow
TestControl.OnLoaded: TextToShow=
The problem here is that you just can't rely on the bindings being completed when the Loaded event fires.
If you attach a PropertyChangedCallback to your TextToShow property you can see that it's fired after the Loaded event of TestControl when you set the DataContext in the Loaded event of your MainWindow.
Its not required to set the DataContext here, rather than you could go for Binding with RelativeSource..
<TextBlock Text="{Binding TextToShow, RelativeSource="{RelativeSource FindAncestor, AncestorType=UserControl}}" />
<local:TestControl TextToShow="{Binding TextToBind, RelativeSource="{RelativeSource Self}}" />

WPF bind point to UserControl

I have a user control that contains 2 DoubleUpDown, I have bound point to that controls
<DoubleUpDown x:Name="X" Grid.Column="1" Grid.Row="0" Value="{Binding Path=Value.X, Mode=TwoWay" />
<DoubleUpDown x:Name="Y" Grid.Column="1" Grid.Row="1" Value="{Binding Path=Value.Y, Mode=TwoWay}" />
controls get updated pretty well when I change Value from outside, but Value stays unchanged when I change controls data.
I bound Value to user control from code inside
Point2DEditorView editor = new Point2DEditorView();
Binding binding = new Binding("Value");
binding.Mode = BindingMode.TwoWay;
editor.SetBinding(Point2DEditorView.ValueProperty, binding);
and Point2DEditorView.Value also changed when I insert new coordinates into controls. But that does not affect bound Value.
Point is a value type data. Because of this when you bind it to control boxing and unboxing occurs. For more information see this. So, you may easy solve this problem by creating your own class (not struct!):
class MyPoint
{
public int X { set; get; }
public int Y { set; get; }
}
And then bind this objects to your control and you will see that all works as you expect.
Update
First of all your DoubleUpDown is'n in standart FCL and I think your problem in it. There is a simple example where all works as expect. I created a simple UpDown control for it:
Point class
public class Point2D : INotifyPropertyChanged
{
private double x;
private double y;
public double X
{
set
{
if (value.Equals(x)) return;
x = value;
OnPropertyChanged();
}
get { return x; }
}
public double Y
{
set
{
if (value.Equals(y)) return;
y = value;
OnPropertyChanged();
}
get { return y; }
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
UpDown xaml
<UserControl x:Name="doubleUpDown" x:Class="PointBind.DoubleUpDown"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" d:DesignWidth="105" Height="33">
<StackPanel Orientation="Horizontal" DataContext="{Binding ElementName=doubleUpDown}">
<TextBox Margin="5,5,0,5" Width="50" Text="{Binding Value}" />
<Button x:Name="Up" x:FieldModifier="private" Margin="5,5,0,5" Content="˄" Width="20" Click="Up_Click" />
<Button x:Name="Down" x:FieldModifier="private" Margin="0,5,0,5" Content="˅" Width="20" Click="Down_Click" />
</StackPanel>
</UserControl>
UpDown .cs
public partial class DoubleUpDown : UserControl
{
public double Value
{
get { return (double)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
// Using a DependencyProperty as the backing store for Value. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(double), typeof(DoubleUpDown), new PropertyMetadata(0.0));
public DoubleUpDown()
{
InitializeComponent();
DataContext = this;
}
private void Up_Click(object sender, RoutedEventArgs e)
{
Value++;
}
private void Down_Click(object sender, RoutedEventArgs e)
{
Value--;
}
}
Point2DEditorView xaml
<UserControl x:Name="point2DEditorView" x:Class="PointBind.Point2DEditorView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
xmlns:local="clr-namespace:PointBind"
d:DesignHeight="300" d:DesignWidth="300">
<StackPanel>
<local:DoubleUpDown Value="{Binding Point.X, ElementName=point2DEditorView, Mode=TwoWay}"/>
<local:DoubleUpDown Value="{Binding Point.Y, ElementName=point2DEditorView, Mode=TwoWay}"/>
</StackPanel>
</UserControl>
UpDown .cs
public partial class Point2DEditorView : UserControl
{
public Point2D Point
{
get { return (Point2D)GetValue(PointProperty); }
set { SetValue(PointProperty, value); }
}
// Using a DependencyProperty as the backing store for Point. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PointProperty =
DependencyProperty.Register("Point", typeof (Point2D), typeof (Point2DEditorView),
new PropertyMetadata(new Point2D {X = 10, Y = 20}));
public Point2DEditorView()
{
InitializeComponent();
}
}
Test form xaml
<Window x:Class="PointBind.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PointBind"
Title="MainWindow" Height="350" Width="525">
<Grid>
<local:Point2DEditorView x:Name="pointEditor"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="39,121,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
</Grid>
</Window>
And test form .cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
pointEditor.Point = new Point2D{X = 300, Y = 400};
}
}
Hope this helps.

Binding on DependencyProperty of custom User Control not updating on change

I'm having difficulties with databinding on my custom user control (s). I created an example project to highlight my problem. I'm completely new to WPF and essentially MVVM as well, so bear with me...
I created a simple view that uses databinding two ways. The databinding on the built-in control works just fine. My custom control doesn't... I put a breakpoint in the PropertyChangedCallback of my control. It gets hit once on startup, but then never again. Meanwhile, the label I have bound to the same value is happily counting down.
What am I missing? My example project follows:
The main window:
<Window x:Class="WpfMVVMApp.MainWindow"
xmlns:local="clr-namespace:WpfMVVMApp"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.DataContext>
<local:CountdownViewModel />
</Grid.DataContext>
<Label Name="custName" Content="{Binding Path=Countdown.ChargeTimeRemaining_Mins}" Height="45" VerticalAlignment="Top"></Label>
<local:UserControl1 MinutesRemaining="{Binding Path=Countdown.ChargeTimeRemaining_Mins}" Height="45"></local:UserControl1>
</Grid>
</Window>
Here's my model:
namespace WpfMVVMApp
{
public class CountdownModel : INotifyPropertyChanged
{
private int chargeTimeRemaining_Mins;
public int ChargeTimeRemaining_Mins
{
get
{
return chargeTimeRemaining_Mins;
}
set
{
chargeTimeRemaining_Mins = value;
OnPropertyChanged("ChargeTimeRemaining_Mins");
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
}
The ViewModel:
namespace WpfMVVMApp
{
public class CountdownViewModel
{
public CountdownModel Countdown { get; set; }
DispatcherTimer timer;
private const int maxMins = 360;
public CountdownViewModel()
{
Countdown = new CountdownModel { ChargeTimeRemaining_Mins = 60 };
// Setup timers
timer = new DispatcherTimer();
timer.Tick += new EventHandler(this.SystemChargeTimerService);
timer.Interval = new TimeSpan(0, 0, 1);
timer.Start();
}
private void SystemChargeTimerService(object sender, EventArgs e)
{
//convert to minutes remaining
// DEMO CODE - TODO: Remove
this.Countdown.ChargeTimeRemaining_Mins -= 1;
}
}
}
Here's the XAML for my user control:
<UserControl x:Class="WpfMVVMApp.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Label Name="Readout"></Label>
</Grid>
</UserControl>
And here's the code behind the user control:
namespace WpfMVVMApp
{
public partial class UserControl1 : UserControl
{
#region Dependency Properties
public static readonly DependencyProperty MinutesRemainingProperty =
DependencyProperty.Register
(
"MinutesRemaining", typeof(int), typeof(UserControl1),
new UIPropertyMetadata(10, new PropertyChangedCallback(minutesRemainChangedCallBack))
);
#endregion
public int MinutesRemaining
{
get
{
return (int)GetValue(MinutesRemainingProperty);
}
set
{
SetValue(MinutesRemainingProperty, value);
}
}
static void minutesRemainChangedCallBack(DependencyObject property, DependencyPropertyChangedEventArgs args)
{
UserControl1 _readout = (UserControl1)property;
_readout.MinutesRemaining = (int)args.NewValue;
_readout.Readout.Content = _readout.MinutesRemaining;
}
public UserControl1()
{
InitializeComponent();
}
}
}
Your change callback is breaking the binding.
As a skeleton: in your window you have UC.X="{Binding A}" and then in that property change (in UC) you have X=B;. This breaks the binding since in both cases you set X.
To rectify, remove change callback and add this to the label:
Content="{Binding MinutesRemaining, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"
I tried your code works fine the only change i made was to remove the code behind propertychangedcallback you have and databind the Label (Readout) to the dependency property.
USERCONTROL(XAML)
<UserControl x:Class="WpfApplication1.UserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Label Name="Readout" Content="{Binding RelativeSource={RelativeSource
AncestorType=UserControl}, Path=MinutesRemaining}"/>
</Grid>
</UserControl>
USERCONTROL (CODE BEHIND)
public partial class UserControl1 : UserControl
{
#region Dependency Properties
public static readonly DependencyProperty MinutesRemainingProperty =
DependencyProperty.Register
(
"MinutesRemaining", typeof(int), typeof(UserControl1),
new UIPropertyMetadata(10)
);
#endregion
public int MinutesRemaining
{
get
{
return (int)GetValue(MinutesRemainingProperty);
}
set
{
SetValue(MinutesRemainingProperty, value);
}
}
public UserControl1()
{
InitializeComponent();
}
}

How to display a listbox with the populated items on click of a menu item in XAML/C#

I have a context menu in my XAML file. When I click on this menu item, I want to display a listbox to the user with a list of data populated from a backend call. How can I achieve this? I am a novice in XAML/WPF.
This would be your xaml:
<Window x:Class="MyWpfApp.MyWindow"
xmlns:cmd="clr-namespace:MyWpfApp.MyCommandsNamespace"
xmlns:vm="clr-namespace:MyWpfApp.MyViewModelsNamespace"
...>
<Window.Resources>
<DataTemplate x:Key="MyItemTemplate" DataType="{x:Type vm:MyItemClass}">
<TextBlock Text="{Binding MyItemText}"/>
</DataTemplate>
</Window.Resources>
<Window.CommandBindings>
<CommandBinding Command="{x:Static cmd:MyCommandsClass.MyCommand1}" Executed="ExecuteMyCommand" CanExecute="CanExecuteMyCommand"/>
</Window.CommandBindings>
<Window.ContextMenu>
<ContextMenu>
<MenuItem Header="MyMenuItem1"
CommandTarget="{Binding}"
Command="{x:Static cmd:MyCommandsClass.MyCommand1}"/>
</ContextMenu>
</Window.ContextMenu>
<Grid>
<ItemsControl ItemsSource="{Binding MyList}"
ItemTemplate="{StaticResource MyItemTemplate}"/>
</Grid>
</Window>
and this would be your cs code:
public MyWindow()
{
VM = new MyViewModelsNamespace.MyViewModel();
this.DataContext = VM;
InitializeComponent();
}
public void ExecuteMyCommand(object sender, ExecutedRoutedEventArgs e)
{
VM.MyList.Add(new MyItemClass{MyItemText="some text"});
}
public void CanExecuteMyCommand(object sender, CanExecuteRoutedEventArgs e)
{
if (...) e.CanExecute = false;
else e.CanExecute = true;
}
where MyViewModel is something like:
public class MyViewModel : DependencyObject
{
//MyList Observable Collection
private ObservableCollection<MyItemClass> _myList = new ObservableCollection<MyItemClass>();
public ObservableCollection<MyItemClass> MyList { get { return _myList; } }
}
and MyItemClass is something like:
public class MyItemClass : DependencyObject
{
//MyItemText Dependency Property
public string MyItemText
{
get { return (string)GetValue(MyItemTextProperty); }
set { SetValue(MyItemTextProperty, value); }
}
public static readonly DependencyProperty MyItemTextProperty =
DependencyProperty.Register("MyItemText", typeof(string), typeof(MyItemClass), new UIPropertyMetadata("---"));
}
I forgot to mention command:
public static class MyCommandsClass
{
public static RoutedCommand MyCommand1 = new RoutedCommand();
}

Categories