I have a problem with binding an DependencyProperty of type ICommand.
This is my custom user control:
<UserControl x:Class="HexEditor.Controls.NavButton"
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:local="using:HexEditor.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="300"
d:DesignWidth="400"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
mc:Ignorable="d">
<ToggleButton x:Name="toggleWrap"
Width="140"
Height="48"
Background="Transparent"
BorderThickness="0"
Command="{Binding Command}"
CommandParameter="{Binding CommandParameter}"
IsChecked="{Binding IsChecked}">
<Grid Width="140">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<FontIcon Margin="6,0,0,0"
Glyph="{Binding Icon}" />
<TextBlock Grid.Column="1"
Margin="32,0,0,0"
Text="{Binding Title}" />
</Grid>
</ToggleButton>
</UserControl>
This is code behind of my control:
public sealed partial class NavButton : UserControl
{
public NavButton()
{
this.InitializeComponent();
}
public static readonly DependencyProperty IconProperty =
DependencyProperty.Register("Icon", typeof(string), typeof(FontIcon), new PropertyMetadata(""));
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(string), typeof(TextBlock), new PropertyMetadata(""));
public static readonly DependencyProperty IsCheckedProperty =
DependencyProperty.Register("IsChecked", typeof(bool), typeof(ToggleButton), new PropertyMetadata(""));
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register("Command", typeof(ICommand), typeof(ToggleButton), new PropertyMetadata(""));
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.Register("CommandParameter", typeof(object), typeof(ToggleButton), new PropertyMetadata(""));
public string Icon
{
get { return (string)GetValue(IconProperty); }
set { SetValue(IconProperty, value); }
}
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
public bool IsChecked
{
get { return Convert.ToBoolean(GetValue(IsCheckedProperty)); }
set { SetValue(IsCheckedProperty, value); }
}
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
public object CommandParameter
{
get { return GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
}
And this is a page where i use my control:
<UserControl x:Class="HexEditor.Common.RootFrame"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Controls="using:HexEditor.Controls"
xmlns:Interactions="using:Microsoft.Xaml.Interactions.Core"
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:HexEditor.Common"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="300"
d:DesignWidth="400"
DataContext="{Binding CommonViewModel,
Source={StaticResource Locator}}"
mc:Ignorable="d">
<Grid Background="White">
<SplitView x:Name="navSplitView"
Width="Auto"
DisplayMode="CompactOverlay"
OpenPaneLength="140">
<SplitView.Pane>
<StackPanel>
<ToggleButton x:Name="hamBtn"
Width="48"
Height="48"
BorderThickness="0">
<FontIcon Glyph="" />
</ToggleButton>
<Controls:NavButton Title="Home"
Command="{Binding NavigationCommand}"
CommandParameter="HomePage"
Icon=""
IsChecked="True" />
<Controls:NavButton Title="Settings"
Command="{Binding NavigationCommand}"
CommandParameter="SettingsPage"
Icon=""
IsChecked="False" />
</StackPanel>
</SplitView.Pane>
<SplitView.Content>
<Frame x:Name="NavFrame" />
</SplitView.Content>
<Interactivity:Interaction.Behaviors>
<Interactions:DataTriggerBehavior Binding="{Binding IsChecked,
ElementName=hamBtn}"
Value="True">
<Interactions:ChangePropertyAction PropertyName="IsPaneOpen"
TargetObject="{Binding ElementName=navSplitView}"
Value="True" />
</Interactions:DataTriggerBehavior>
<Interactions:DataTriggerBehavior Binding="{Binding IsChecked,
ElementName=hamBtn}"
Value="False">
<Interactions:ChangePropertyAction PropertyName="IsPaneOpen"
TargetObject="{Binding ElementName=navSplitView}"
Value="False" />
</Interactions:DataTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</SplitView>
</Grid>
</UserControl>
Here's the ViewModel:
public class CommonViewModel : ViewModelBase
{
public CommonViewModel()
{
this.NavigationCommand = new RelayCommand<NavigationSource>(this.ExecuteNavigationCommand);
}
public ICommand NavigationCommand { get; private set; }
private void ExecuteNavigationCommand(NavigationSource state)
{
NavigationProvider.Instance.NavigateTo(state);
}
}
When compiling, exception appears:
Exception thrown: 'System.InvalidCastException' in HexEditor.exe
'HexEditor.exe' (CoreCLR: CoreCLR_UWP_Domain): Loaded 'C:\Users\Root\documents\visual studio 2015\Projects\HexEditor\HexEditor\bin\x86\Debug\AppX\System.Resources.ResourceManager.dll'. Module was built without symbols.
Exception thrown: 'Windows.UI.Xaml.Markup.XamlParseException' in HexEditor.exe
WinRT information: Failed to assign to property 'HexEditor.Controls.NavButton.Command'. [Line: 29 Position: 41]
An exception of type 'Windows.UI.Xaml.Markup.XamlParseException' occurred in HexEditor.exe but was not handled in user code
WinRT information: Failed to assign to property 'HexEditor.Controls.NavButton.Command'. [Line: 29 Position: 41]
Additional information: The text associated with this error code could not be found.
Failed to assign to property 'HexEditor.Controls.NavButton.Command'. [Line: 29 Position: 41]
What i'm doing wrong?
I think the problem is that you have default values of "" for dependency properties of type bool and ICommand (new PropertyMetadata("") in both cases). You can't cast a string to either one, and that will cause an exception to be thrown. IsChecked should default to false, and Command should default to null.
This may or may not be relevant to the exact issue you're asking about, but it matters too: The third parameter of DependencyProperty.Register() should be the type of the owning class. That's typeof(NavButton) in your case, for all of its dependency properties.
Related
I'm trying to bind a property from a user control to a window but get error
Object of type 'System.Windows.Data.Binding' cannot be converted to type 'System.String'.
When I was searching the error usually the people didn't create a Dependency Property or that the problem may be because the two Way binding but didn't find a solution
I know that if I give the usercontrol a name and then get the value but I want to use binding
UserControl.xaml
<UserControl x:Name="ctb" x:Class="ChatClient.CustomControls.CustomTextBox"
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"
xmlns:local="clr-namespace:ChatClient.CustomControls"
mc:Ignorable="d"
d:DesignHeight="20" d:DesignWidth="350">
<Grid>
<Border CornerRadius="8"
Background="#3e4147">
<Grid>
<TextBox VerticalAlignment="Stretch"
VerticalContentAlignment="Center"
HorizontalAlignment="Stretch"
Background="Transparent"
x:Name="TextBox"
TextWrapping="Wrap"
BorderThickness="0"
Foreground="Gray"
CaretBrush="Gray"
Margin="8,0,0,0"
Text="{Binding ElementName=ctb, Path=InputText}">
</TextBox>
<TextBlock IsHitTestVisible="False"
Text="{Binding ElementName=ctb, Path=PlaceHolder}"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="10,0,0,0"
Foreground="DarkGray">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Text, ElementName=TextBox}" Value="">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Grid>
</Border>
</Grid>
</UserControl>
UserControl.xaml.cs
public CustomTextBox()
{
InitializeComponent();
}
public static readonly DependencyProperty InputTextProp = DependencyProperty.Register(
nameof(InputText),
typeof(string),
typeof(CustomTextBox),
new PropertyMetadata(OnValueChangedText));
public static readonly DependencyProperty PlaceHolderProp = DependencyProperty.Register("PlaceHolder", typeof(string),
typeof(CustomTextBox),
new PropertyMetadata(null));
public string InputText
{
get { return (string)GetValue(InputTextProp); }
set { SetValue(InputTextProp, value); }
}
public string PlaceHolder
{
get { return (string)GetValue(PlaceHolderProp); }
set { SetValue(PlaceHolderProp, value); }
}
private static void OnValueChangedText(DependencyObject sender,DependencyPropertyChangedEventArgs e)
{
CustomTextBox customTextBox = sender as CustomTextBox;
customTextBox.InputText = (string)e.NewValue;
}
MainWindow.xaml
<customcontrols:CustomTextBox InputText="{Binding UserName}"
PlaceHolder="UserName"
Margin="0,0,0,20" />
Dependency property name must end with "Property", not "Prop":
public static readonly DependencyProperty InputTextProperty = DependencyProperty.Register
(
nameof(InputText),
typeof(string),
typeof(CustomTextBox),
new PropertyMetadata(string.Empty)
);
fix it for all usages and all properties.
OnValueChangedText callback implemented incorrectly and should be removed from metadata
This question already has an answer here:
XAML binding not working on dependency property?
(1 answer)
Closed 2 years ago.
I would like to display my score point in a textbox, even if the textbox.Text get the value, in GUI i can't see my score.
<UserControl x:Class="WpfCyberPunk.UserControls.UserControlPlaying"
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"
xmlns:local="clr-namespace:WpfCyberPunk.UserControls"
mc:Ignorable="d"
d:DesignHeight="350" Width="Auto" d:DataContext="{d:DesignData }">
<Grid Name="PlayingGrid" Margin="0,0,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid Row="0" HorizontalAlignment="Left">
<StackPanel Name="SkPn_Score" Orientation="Horizontal">
<TextBlock HorizontalAlignment="Left" Margin="10,1,0,0" TextWrapping="Wrap" Text="Point de départ" VerticalAlignment="Center" Height="25" Width="100"/>
<TextBox x:Name = "tBx_StartPt" Text="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=ScoreText,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged }" TextChanged="TBx_StartPt_OnTextChanged" FontSize="10" HorizontalAlignment="Left" Margin="10,1,0,0" TextWrapping="Wrap" VerticalAlignment="Center" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Height="25" Width="50"/>
</StackPanel>
</Grid>
IN cs, I have
public partial class UserControlPlaying : UserControl
{
private string _score;
private int _point;
//public event DependencyProperty PropertyChanged;
public string Score
{
get => _score;
set
{
_score = value;
SetValue(ValueProperty, _score);
}
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Score", typeof(string), ownerType: typeof(UserControlPlaying), new PropertyMetadata(""));
And in my class, i have made an event to see, the new value
private void TBx_StartPt_OnTextChanged(object sender, TextChangedEventArgs e)
{
string newScore = tBx_StartPt.Text;
}
In debug, newScore get the new value.
I don't understand, anything does not display in GUI.
Thank you for your help.
You dependency property declaration is wrong. It must look like this:
public string Score
{
get { return (string)GetValue(ScoreProperty); }
set { SetValue(ScoreProperty, value); }
}
public static readonly DependencyProperty ScoreProperty =
DependencyProperty.Register(
nameof(Score),
typeof(string),
typeof(UserControlPlaying),
new PropertyMetadata(""));
And fix the binding in the textbox:
<TextBox Text="{Binding RelativeSource={RelativeSource AncestorType=UserControl},
Path=Score,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" .../>
I'm currently working on a Windows Universal App. I'm still quite new to XAML in general but have had some experience with it.
The issue I'm having is around binding inside a UserControl. I've looked around and can't find an answer to my specific issue.
I have a XAML page that is linked to a ViewModel, this all works fine. Then on that page I'm using a UserControl that is basically just a panel with a header that contains some content. In the content of that panel I have another UserControl that basically just consists of a Label and TextBox.
When I bind things from my ViewModel to the ContentPanel UserControl everything works fine, it picks up my ViewModel context and binds correctly.
However, When I try to bind to the LabelledTextbox UserControl that is contained withing the ContentPanel the binding fails because it is just looking for the property that is on the ViewModel on the ContentPanel instead.
See below for the code I have
Page.xaml
<!--Page.xaml-->
<cc:ContentPanel PanelHeading="LEFT FOOT: Measurements" PanelHeadingBackground="{StaticResource OPCare.PanelHeader}">
<StackPanel>
<cc:LabelledTextbox LabelText="Malleoli Width" Text="test" />
<cc:LabelledTextbox LabelText="Met Head Width" />
</StackPanel>
</cc:ContentPanel>
ContentPanel.xaml
<!--ContentPanel UserControl-->
<UserControl
x:Class="OrthoticTabletApp.Controls.ContentPanel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:OrthoticTabletApp.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400"
x:Name="Parent">
<Grid DataContext="{Binding ElementName=Parent}">
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Padding="10" Grid.Column="0" Grid.Row="0" Height="50" Background="{Binding Path=PanelHeadingBackground}">
<TextBlock Height="30" LineHeight="30" Text="{Binding Path=PanelHeading}" />
</Grid>
<Grid Padding="10" Grid.Column="0" Grid.Row="1" Background="White">
<ContentPresenter Content="{Binding Path=PanelBody}" />
</Grid>
</Grid>
</UserControl>
ContentPanel.xaml.cs
[ContentProperty(Name = "PanelBody")]
public sealed partial class ContentPanel : UserControl
{
public static readonly DependencyProperty PanelHeadingProperty = DependencyProperty.Register("PanelHeading", typeof(string), typeof(ContentPanel), new PropertyMetadata(""));
public string PanelHeading
{
get
{
return (string)GetValue(PanelHeadingProperty);
}
set
{
SetValue(PanelHeadingProperty, value);
}
}
public static readonly DependencyProperty PanelBodyProperty = DependencyProperty.Register("PanelBody", typeof(object), typeof(ContentPanel), new PropertyMetadata(null));
public object PanelBody
{
get
{
return (object)GetValue(PanelBodyProperty);
}
set
{
SetValue(PanelBodyProperty, value);
}
}
public Brush PanelHeadingBackground
{
get { return (Brush)GetValue(PanelHeadingBackgroundProperty); }
set { SetValue(PanelHeadingBackgroundProperty, value); }
}
public static readonly DependencyProperty PanelHeadingBackgroundProperty =
DependencyProperty.Register("PanelHeadingBackground", typeof(Brush), typeof(ContentPanel), new PropertyMetadata(null));
public ContentPanel()
{
this.InitializeComponent();
}
}
LabelledTextbox.xaml
<UserControl
x:Class="OrthoticTabletApp.Controls.LabelledTextbox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:OrthoticTabletApp.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="50"
d:DesignWidth="400"
x:Name="Parent">
<Grid DataContext="{Binding ElementName=Parent}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" Padding="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="15" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Path=LabelText}" />
</Grid>
<Grid Grid.Column="1" Padding="10">
<TextBox Text="{Binding Path=Text}" />
</Grid>
</Grid>
</UserControl>
LabelledTextbox.xaml.cs
public sealed partial class LabelledTextbox : UserControl
{
public string LabelText
{
get { return (string)GetValue(LabelTextProperty); }
set { SetValue(LabelTextProperty, value); }
}
// Using a DependencyProperty as the backing store for LabelText. This enables animation, styling, binding, etc...
public static readonly DependencyProperty LabelTextProperty =
DependencyProperty.Register("LabelText", typeof(string), typeof(LabelledTextbox), new PropertyMetadata(null));
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
// Using a DependencyProperty as the backing store for Text. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(LabelledTextbox), new PropertyMetadata(null));
public LabelledTextbox()
{
this.InitializeComponent();
}
}
However, When I try to bind to the LabelledTextbox UserControl that is contained withing the ContentPanel the binding fails because it is just looking for the property that is on the ViewModel on the ContentPanel instead.
If I correctly understood what you've done, some properties of your ContentPanel are bound to the data model in the page's viewmodel, and properties of your LabelledTextbox are bound to the data model in other viewmodel?
If so, you can specify the DataContext for LabelledTextbox for StackPanel which is inside the ContentPanel, just for example like this:
<cc:ContentPanel PanelHeading="{x:Bind Heading}" PanelHeadingBackground="Azure">
<StackPanel>
<StackPanel.DataContext>
<local:LabelledTextboxViewModel x:Name="VM" />
</StackPanel.DataContext>
<cc:LabelledTextbox LabelText="{x:Bind VM.Lable1}" Text="test" />
<cc:LabelledTextbox LabelText="{x:Bind VM.Lable2}" />
</StackPanel>
</local:ContentPanel>
In your page's viewmodel, you can make the data model for ContentPanel and initialize the data for example like this:
public BlankPage3ViewModel()
{
Heading = "LEFT FOOT: Measurements";
}
public string Heading { get; set; }
In the LabelledTextboxViewModel you can code for example like this:
public class LabelledTextboxViewModel
{
public LabelledTextboxViewModel()
{
Lable1 = "Malleoli Width";
Lable2 = "Met Head Width";
}
public string Lable1 { get; set; }
public string Lable2 { get; set; }
}
Usually when we follow the MVVM pattern to develop a project, the data model should not be included inside of the viewmodel, I'm here just for clear and easy delivery, the key point is that you can specify different DataContext for different controls in the same page.
I created an custom UserControl which includes an Ellipse and a Label. The Label Content and the Color of the Ellipse is binded:
The Binding-Properties are DependencyProperties.
The color of the Ellipse is depended on the Status, which is a bool (a converter creates the Color)
This is the UserControl1.xaml:
<UserControl x:Class="Plugin_UPS.Views.UserControl1"
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:Converters="clr-namespace:WPF_Prism.Infrastructure.Converters.Ups;assembly=WPF_Prism.Infrastructure"
mc:Ignorable="d"
x:Name="UC1"
d:DesignWidth="200" Height="40">
<UserControl.Resources>
<ResourceDictionary>
<Converters:BoolToColorConverter x:Key="BoolToColorConverter"/>
</ResourceDictionary>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Height="42" Width="504">
<StackPanel HorizontalAlignment="Left" Margin="0,0,0,0" Height="Auto" Width="Auto" Grid.Column="0" Grid.Row="0">
<Grid Height="Auto" Width="Auto" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0,0,0,0"
MinWidth="200" MaxWidth="200" MinHeight="35" MaxHeight="40">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Ellipse HorizontalAlignment="Left" VerticalAlignment="Center" Grid.Column="0" Grid.Row="0"
Fill="{Binding Status, Converter={StaticResource BoolToColorConverter}, UpdateSourceTrigger=PropertyChanged}"
Height="15"
Width="15"
StrokeThickness="1"
Stroke="Black">
</Ellipse>
<Label Content="{Binding Text}" Height="Auto" Width="Auto" Margin="0,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Center" FontSize="16" Grid.Column="1" Grid.Row="0" />
</Grid>
</StackPanel>
</Grid>
</UserControl>
This is the UserControl1.xaml.cs:
namespace Plugin_UPS.Views
{
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(UserControl1));
public bool Status
{
get { return (bool)GetValue(StatusProperty); }
set { SetValue(StatusProperty, value); }
}
public static readonly DependencyProperty StatusProperty =
DependencyProperty.Register("Status", typeof(bool), typeof(UserControl1));
}
}
This is my UPSViewModel.cs:
namespace Plugin_UPS.ViewModel
{
public class UPSViewModel
{
public UPSViewModel()
{
}
public string UpsModelText { get { return "Model"; } }
private bool replaceBatteryCondition;
public bool ReplaceBatteryCondition { get { return replaceBatteryCondition; } set { replaceBatteryCondition = value; } }
}
}
This is my UPSView.xaml:
(here I implement the UserControl1)
<UserControl x:Class="Plugin_UPS.Views.UPSView"
x:Name="UPSUC"
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"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
xmlns:local="clr-namespace:Plugin_UPS"
xmlns:Controls="clr-namespace:WPF_Prism.Controls.Controls;assembly=WPF_Prism.Controls"
xmlns:ViewModel="clr-namespace:Plugin_UPS.ViewModel"
xmlns:Views="clr-namespace:Plugin_UPS.Views"
d:DataContext="{d:DesignInstance ViewModel:UPSViewModel}"
mc:Ignorable="d"
d:DesignHeight="840" d:DesignWidth="1260">
<Grid>
<StackPanel>
<Views:UserControl1 Margin="10,20,10,10" DataContext="{Binding RelativeSource={RelativeSource Self}}" Text="{Binding UpsModelText}" Status="{Binding ReplaceBatteryCondition}"></Views:UserControl1>
</StackPanel>
</Grid>
</UserControl>
But the binding for "Status" and "Text" is not working.
(Status="True" or Text="Model" is working).
Do you have any ideas what the problem could be?
Is there a problem with the DataContext?
best regards
Phil
You must not set the UserControl's DataContext to itself, as done by
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Remove that assignment and write
<Views:UserControl1 Margin="10,20,10,10"
Text="{Binding UpsModelText}"
Status="{Binding ReplaceBatteryCondition}" />
Now you'll have to specify the source of the bindings in the UserControl's XAML.
There are multiple ways to do that, one of them is to set the RelativeSource property like this:
<Label Content="{Binding Text,
RelativeSource={RelativeSource AncestorType=UserControl}}" ... />
<Ellipse Fill="{Binding Status,
RelativeSource={RelativeSource AncestorType=UserControl},
Converter={StaticResource BoolToColorConverter}}" ... />
Note that setting UpdateSourceTrigger=PropertyChanged on the Fill Binding doesn't make sense.
I have a XAML like:
<UserControl x:Class="Book.CustomControls.HeaderedComboBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Width="200" Height="50">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Margin="2,2" VerticalAlignment="Center" Text="{Binding Header}" FontWeight="{Binding HeaderFontWeight}"/>
<ComboBox Grid.Row="1" Margin="2,2" VerticalAlignment="Center" ItemsSource="{Binding ItemsSource, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding SelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
</UserControl>
The cs-file therefor is:
public partial class HeaderedComboBox : UserControl
{
public HeaderedComboBox()
{
this.InitializeComponent();
this.HeaderFontWeight = FontWeights.Normal;
}
public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register("Header", typeof(string), typeof(HeaderedComboBox));
public static readonly DependencyProperty HeaderFontWeightProperty = DependencyProperty.Register("HeaderFontWeight", typeof(FontWeight), typeof(HeaderedComboBox));
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(HeaderedComboBox));
public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", typeof(object), typeof(HeaderedComboBox));
public string Header
{
get { return (string)GetValue(HeaderProperty); }
set { SetValue(HeaderProperty, value); }
}
public FontWeight HeaderFontWeight
{
get { return (FontWeight)GetValue(HeaderFontWeightProperty); }
set { SetValue(HeaderFontWeightProperty, value); }
}
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public object SelectedItem
{
get { return GetValue(SelectedItemProperty); }
set { SetValue(SelectedItemProperty, value); }
}
}
I tried to use this UserControl in any Window with
<customControls:HeaderedComboBox Header="Category" ItemsSource="{Binding Categories}"/>
Categories is just an ObservableCollection<string>.
Unfortunately I don't see any items in the ComboBox. At the moment I have no idea, what I'm doing wrong. Any ideas?
System.Windows.Data Error: 40 : BindingExpression path error: 'Categories' property not found on 'object' ''HeaderedComboBox' (Name='')'. BindingExpression:Path=Categories; DataItem='HeaderedComboBox' (Name=''); target element is 'HeaderedComboBox' (Name=''); target property is 'ItemsSource' (type 'IEnumerable')
Your DataContext is set to HeaderedCombobox and there system is looking for a Categories. Property Header worked since you put a text into it without binding. Possible solution
<Window x:Class="WpfApplication5.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:local="clr-namespace:WpfApplication5" Name="window">
<Grid>
<local:HeaderedComboBox Header="Category" ItemsSource="{Binding ElementName=window, Path=DataContext.Categories}"/>
</Grid>