BindingExpression path error: 'DisplayName' property not found on 'object' - wpf

I'm new to wpf and I'm trying use a DataTemplate to create menu, to learn how to use DataTemplates.
I get the following binding error and no text appears in the control and I can't see why.
Binding Error
System.Windows.Data Error: 40 : BindingExpression path error: 'DisplayName' property not found on 'object' ''StartOptionsViewModel' (HashCode=7730701)'. BindingExpression:Path=DisplayName; DataItem='StartOptionsViewModel' (HashCode=7730701); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
MainWindow.XAML is:
<Window x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Colin's Test Application" Width="600" Height="400">
<Window.Resources>
<!-- WIZARD STEP TEMPLATE -->
<DataTemplate x:Key="OptionsTemplate">
<Border x:Name="bdOuter" BorderBrush="Black" BorderThickness="0,0,1,1" CornerRadius="12" Margin="1,1,1,12" Opacity="1" SnapsToDevicePixels="True" >
<Border x:Name="bdInner" Background="#FFFEFEFE" BorderBrush="Brown" BorderThickness="2,2,1,1" CornerRadius="12" Padding="2" >
<TextBlock x:Name="txt" Margin="4,0,0,0" Foreground="Black" Text="{Binding Path=DisplayName, Mode=OneWayToSource}" />
</Border>
</Border>
</DataTemplate>
</Window.Resources>
<StackPanel VerticalAlignment="Center">
<ItemsControl
ItemsSource="{Binding Path=StartOptions}"
ItemTemplate="{StaticResource OptionsTemplate}"
/>
</StackPanel>
</Window>
My MainWindoViewModel.cs
public partial class MainWindowViewModel
{
private List<StartOptionsViewModel> _listStartOptionsVM = new List<StartOptionsViewModel>();
public MainWindowViewModel()
{
_listStartOptionsVM.AddRange(new StartOptionsViewModel[]
{
new StartOptionsViewModel(new StartOption("New Application", StartOption.StartOptionTypes.Button)),
new StartOptionsViewModel(new StartOption("Exit Application", StartOption.StartOptionTypes.Button))
});
}
public ReadOnlyCollection<StartOptionsViewModel> StartOptions
{
get
{
return new ReadOnlyCollection<StartOptionsViewModel>(_listStartOptionsVM);
}
}
}
`
StartOptionsViewModel.cs:
public class StartOptionsViewModel
{
private StartOption m_startOption = null;
public StartOptionsViewModel(StartOption p_startOption)
{
m_startOption = p_startOption;
}
#region Properties
public string DisplayName
{
get { return m_startOption.DisplayName; }
set
{
//...
}
}
#endregion
}

first of all you are binding your textblock mode in wrong way because textbox text never be set from ui means on runtime by user son it' smode can't be onewaytosource it should be one way so first you should have correct that like this..
<TextBlock
x:Name="txt"
Margin="4,0,0,0"
Foreground="Black"
Text="{Binding Path=DisplayName, Mode=OneWay}"
/>
first make it correct and run your code and comment if your problem persists.

Related

Bind header and content dynamically to expander

Firstly I see the type for Header and content for the expander, it says the type is object. I have a user control with name CommonExpanderUserControl as follows,
xaml:
<uwpControls:Expander Header="{Binding HeaderContent}" Content="{Binding MainContent}">
</uwpControls:Expander>
In xaml.cs (DataContext is set to this)
public static readonly DependencyProperty HeaderContentProperty =
DependencyProperty.Register("HeaderContent", typeof(object), typeof(CommonExpanderUserControl), new
PropertyMetadata(null));
public object HeaderContent
{
get { return (object)GetValue(HeaderContentProperty); }
set { SetValue(HeaderContentProperty, value); }
}
public static readonly DependencyProperty MainContentProperty =
DependencyProperty.Register("MainContent", typeof(ContentControl), typeof(CommonExpanderUserControl), new
PropertyMetadata(null));
public ContentControl MainContent
{
get { return (ContentControl)GetValue(MainContentProperty); }
set { SetValue(MainContentProperty, value); }
}
Now I am using this UserControl somewhere outside as follows,
<UserControl.Resources>
<ContentControl x:Key="Header">
<Grid x:Name="ExpanderHeaderGrid" HorizontalAlignment="Stretch" Padding="0" Margin="0"
Background="{Binding LisSharedSettings.ChangeHeaderColor,Converter={StaticResource BoolToSolidBrushConverter}}">
<TextBlock x:Name="TextBlockLisSharedSettingsTitle"
x:Uid="/Application.GlobalizationLibrary/Resources/InstrumentSettingsViewLisSettingsTextBlockTitle"
Style="{StaticResource TextBlockStyleSectionHeader}"/>
</Grid>
</ContentControl>
<ContentControl x:Key="Body">
Some content here.
</ContentControl>
</UserControl.Resources>
<Grid>
<local:CommonExpanderUserControl HeaderContent="{StaticResource Header}" MainContent="{StaticResource Body}"/>
</Grid>
Binding Content control like that simply doesn't work. If I remove the MainContent binding and bind only the Header, it says object reference not set to an instance of an object. Please help.
The problem occurs StaticResource binding, we could not bind header with control by StaticResource. And for the scenario the better way is bind HeaderTemplate and send the data source to the header property like the following.
<UserControl.Resources>
<DataTemplate x:Key="HeaderTemplate">
<Grid
x:Name="ExpanderHeaderGrid"
Margin="0"
Padding="0"
HorizontalAlignment="Stretch"
Background="Red"
>
<TextBlock x:Name="TextBlockLisSharedSettingsTitle" Text="{Binding}" />
</Grid>
</DataTemplate>
</UserControl.Resources>
<Grid>
<uwpControls:Expander Header="hello" HeaderTemplate="{StaticResource HeaderTemplate}" />
</Grid>

WPF Textbox Binding Error

I can't figure out why I keep getting this error, and when I make a change to tb_Name TextBox in the GUI the Set in Name never gets called.
System.Windows.Data Error: 40 : BindingExpression path error: 'Name'
property not found on 'object' ''String' (HashCode=2106982518)'.
BindingExpression:Path=Name; DataItem='String' (HashCode=2106982518);
target element is 'TextBox' (Name='tb_Name'); target property is
'Text' (type 'String')
XAML
<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"
xmlns:local="clr-namespace:ConfigStudioUI.Controls" x:Class="ConfigStudioUI.Controls.DeviceTypeTabCtrl"
mc:Ignorable="d" x:Name="DeviceTypeUC" Loaded="DeviceType_Loaded"
d:DesignHeight="400" d:DesignWidth="600" Background="#FF00C8FF"
>
<Grid>
<TabControl Background="#FF00FF99" FontSize="14"
TabStripPlacement="Left" Margin="0, 0, 0, 10" >
<TabItem Name="PropertiesTab" Header="Properties">
<Grid>
<Grid >
<TextBox Text="{Binding Source=DeviceType, Path=Name, Mode=TwoWay}"
TabIndex="0" x:Name="tb_Name" HorizontalAlignment="Stretch" Height="32"
Margin="159,28,5.2,0" VerticalAlignment="Top" />
</Grid>
</Grid>
</TabItem>
</TabControl>
</UserControl>
Code Behind
public partial class DeviceTypeTabCtrl : UserControl
{
public DeviceType DeviceType { get; set; }
public DeviceTypeTabCtrl(DeviceType deviceTypeObject, DeviceTypeGroup
deviceTypeGroupObject)
{
InitializeComponent();
DataContext = this;
this.DeviceType = new DeviceType();
this.DeviceType = deviceTypeObject;
this.tb_Name.Text = deviceTypeObject.Name;
this.DeviceType.DeviceTypeGroupGUID =
deviceTypeGroupObject.DeviceTypeGroupGUID;
}
}
public class DeviceType : INotifyPropertyChanged
{
/// <summary>
/// Name
/// </summary>
public string Name
{
get
{
return this.name;
}
set
{
if (this.name != value)
{
this.name = value;
NotifyPropertyChanged("Name");
}
}
}
}
I ended up finding the answer here: How To Bind a Property to Textbox using MVVM and MVVM toolkit?
I also updated the object name (DeviceTypeObj) to be more clear.
<TextBox Text="{Binding DeviceTypeObj.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" TabIndex="0"
x:Name="tb_Name" HorizontalAlignment="Stretch" Height="32" Margin="159,28,5.2,0" VerticalAlignment="Top" />

Binding disappears on simple user control

I have a simple usercontrol with a single DependencyProperty. I am unable to set bindings on this property. I don't get any exceptions but the bindings just disappear.
I cannot begin to see what is going wrong here. It's so simple.
Here's my usercontrol:
XAML:
<UserControl x:Class="Test.Controls.SimpleUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="ucThis">
<TextBox Text="{Binding Path=MyString, ElementName=ucThis}" />
</UserControl>
Code:
public partial class SimpleUserControl : UserControl
{
public SimpleUserControl()
{
InitializeComponent();
}
public string MyString
{
get { return (string)GetValue(MyStringProperty); }
set { SetValue(MyStringProperty, value); }
}
public static readonly DependencyProperty MyStringProperty =
DependencyProperty.Register("MyString", typeof(string),
typeof(SimpleUserControl), new UIPropertyMetadata("simple user control"));
}
XAML from a test app:
<StackPanel>
<testControls:SimpleUserControl MyString="{Binding Path=TestString}"
x:Name="simpleUC" />
<Label Content="From control" />
<Border Margin="5"
BorderBrush="Black"
BorderThickness="1"
Visibility="{Binding Path=MyString, ElementName=simpleUC, Converter={StaticResource nullVisConv}}">
<ContentPresenter Content="{Binding Path=MyString, ElementName=simpleUC}" />
</Border>
<TextBlock Text="Value from control is null."
Margin="5"
Visibility="{Binding Path=MyString, ElementName=simpleUC, Converter={StaticResource nullVisConv}, ConverterParameter={custom:BooleanValue Value=True}}" />
<Label Content="From binding" />
<Border Margin="5"
BorderBrush="Black"
BorderThickness="1"
Visibility="{Binding Path=TestString, Converter={StaticResource nullVisConv}}">
<ContentPresenter Content="{Binding Path=TestString}" />
</Border>
<TextBlock Text="Value from binding is null."
Margin="5"
Visibility="{Binding Path=TestString, Converter={StaticResource nullVisConv}, ConverterParameter={custom:BooleanValue Value=True}}" />
<TextBox Text="You can set focus here." />
</StackPanel>
The main window for the test app has a property named TestString, is its own DataContext and implements INotifyPropertyChanged correctly. SimpleUserControl.MyString updates as it should but the property it is bound to (TestString) does not. I have inspected this with Snoop; the binding I set on the SimplerUserControl is just not present at run time. What is happening here?
UPDATE
Okay. So if I specify Mode=TwoWay the binding works. That's great. Can anyone explain to me why it behaves this way?
Thanks.
Working as designed :). DPs default to 1-way. Personally, I would change your DependencyProperty.Register() call to make the DP default to two-way. That way you don't have to specify two-way explicitly every time you use it. You'll notice that the framework typically makes DPs two-way by default when you'd want the property to write back. Just a convienience.
Yes you need to provide TwoWay Mode for Dependency Property:
public string MyString
{
get { return (string)GetValue(MyStringProperty); }
set { SetValue(MyStringProperty, value); }
}
public static readonly DependencyProperty MyStringProperty =
DependencyProperty.Register("MyString", typeof(string),
typeof(UserControl1), new FrameworkPropertyMetadata("simple user control", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

Bidning with TextBlock is not Working

I have my Model as:
namespace Forecast.MVVM.WPF.ViewModel
{
public class ApplicationInfoViewModel
{
private string versionNumber;
public ApplicationInfoViewModel()
{
versionNumber = Assembly.GetExecutingAssembly().GetName().Version.ToString();
}
public string VersionNumber
{
get { return versionNumber; }
set { versionNumber = value; }
}
}
And my view I am setting the datContext and getting the values as ;
<UserControl .... xmlns:AppInfo="clr-namespace:Forecast.MVVM.WPF.ViewModel" .../>
<UserControl.Resources>
<AppInfo:ApplicationInfoViewModel x:Key="forecastVersionInfo"/>
</UserControl.Resources>
<Grid>
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding VersionNumber}" VerticalAlignment="Bottom"/>
</Grid>
But I am unable to see the values
1st way :
Try tro replace <UserControl.Resources> by <UserControl.DataContext>
... and delete "x:Key="forecastVersionInfo"".
2nd way :
Or set DataContext="{StaticResource forecastVersionInfo}" on your textBlock.
3rd way :
According to this MSDN page, set the Source property on your textblock binding :
Text="{Binding VersionNumber, Source={StaticResource forecastVersionInfo}}"
You are not setting DataContext
<UserControl.DataContext>
<AppInfo:ApplicationInfoViewModel />
</UserControl.DataContext>
If you want to refer to resource, you can set it on Grid or move resource to App.Resources and apply DataContext as attribute on UserControl
<Grid DataContext="{Binding Path={StaticResource forecastVersionInfo}}">
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding VersionNumber}" VerticalAlignment="Bottom"/>
</Grid>

In WPF how to change a DataTemplate's Textblock's text binding in code?

I have a ListBox whose ItemsSource is bound to a list of objects. The Listbox has a ItemTemplate with a DataTemplate containing a TextBlock. The textblock's Text is bound to the object's Name property (i.e. Text="{Binding Name}").
I would like to provide a radio button to show different views of the same list. For example allow a user to toggle between the Name property and an ID property.
I found a SO answer for this at 2381740 but I also have border and a textbox style set in data template (see code below).
Is there anyway to just reset the Textblock binding? I don't want to have to recreate the entire datatemplate. Actually I'm not even sure how to do that, is there an easy way to translating xaml to code?.
Thanks
Cody
<DataTemplate>
<Border Margin="0 0 2 2"
BorderBrush="Black"
BorderThickness="3"
CornerRadius="4"
Padding="3">
<TextBlock Style="{StaticResource listBoxItemStyle}"
Text="{Binding Name}" />
</Border>
</DataTemplate>
Wallstreet Programmer's solution works well for you because you are using radio buttons. However there is a more general solution that I thought I should mention for future readers of this question.
You can change your DataTemplate to use plain "{Binding}"
<DataTemplate x:Key="ItemDisplayTemplate">
<Border ...>
<TextBlock ...
Text="{Binding}" />
</Border>
</DataTemplate>
Then in code you don't have to recreate a full DataTemplate. All you have to do is recreate this:
<DataTemplate>
<ContentPresenter Content="{Binding Name}" ContentTemplate="{StaticResource ItemDisplayTemplate}" />
</DataTemplate>
which is easy:
private DataTemplate GeneratePropertyBoundTemplate(string property, string templateKey)
{
var template = FindResource(templateKey);
FrameworkElementFactory factory = new FrameworkElementFactory(typeof(ContentPresenter));
factory.SetValue(ContentPresenter.ContentTemplateProperty, template);
factory.SetBinding(ContentPresenter.ContentProperty, new Binding(property));
return new DataTemplate { VisualTree = factory };
}
This is particularly convenient if you have many properties, even in your radio button example.
Just make it simple for yourself and use two textblocks and hide one of them.
XAML:
<Window x:Class="Test.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Window.Resources>
<StackPanel>
<RadioButton Name="nameRadioBtn" Content="Name" IsChecked="True"/>
<RadioButton Name="lengthRadioBtn" Content="Length" />
<ListBox
ItemsSource="{Binding Path=Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Red" BorderThickness="1">
<Grid>
<TextBlock
Text="{Binding .}"
Visibility="{Binding Path=IsChecked, ElementName=nameRadioBtn,
Converter={StaticResource BooleanToVisibilityConverter}}" />
<TextBlock
Text="{Binding Path=Length}"
Visibility="{Binding Path=IsChecked, ElementName=lengthRadioBtn,
Converter={StaticResource BooleanToVisibilityConverter}}" />
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</Window>
Code behind:
using System.Collections.Generic;
using System.Windows;
namespace Test
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
DataContext = this;
}
public IEnumerable<string> Items
{
get
{
return new List<string>() {"Bob", "Sally", "Anna"};
}
}
}
}
You can also use a value converter to pick any property of your data object. You will need to bind to the whole object instead of individual properties. If your data object implements INotifyPropertyChanged then this solution will not work for you.
XAML
<Window x:Class="Test.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Test="clr-namespace:Test"
Height="300" Width="300">
<Window.Resources>
<Test:PropertyPickerConverter x:Key="PropertyPickerConverter" />
</Window.Resources>
<StackPanel>
<RadioButton Content="Name" Click="OnRadioButtonClick" IsChecked="True"/>
<RadioButton Content="Length" Click="OnRadioButtonClick" />
<ListBox
ItemsSource="{Binding Path=Items}"
Name="_listBox">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Red" BorderThickness="1">
<StackPanel>
<TextBlock
Text="{Binding ., Converter={StaticResource PropertyPickerConverter}}" />
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</Window>
code behind:
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace Test
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
_propertyPickerConverter = FindResource("PropertyPickerConverter") as PropertyPickerConverter;
_propertyPickerConverter.PropertyName = "Name";
DataContext = this;
}
public IEnumerable<string> Items
{
get
{
return new List<string>() {"Bob", "Sally", "Anna"};
}
}
private void OnRadioButtonClick(object sender, RoutedEventArgs e)
{
_propertyPickerConverter.PropertyName = (sender as RadioButton).Content as string;
_listBox.Items.Refresh();
}
private PropertyPickerConverter _propertyPickerConverter;
}
public class PropertyPickerConverter : IValueConverter
{
public string PropertyName { get; set; }
#region IValueConverter Members
public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string item = value as string;
switch (PropertyName)
{
case "Name": return item;
case "Length": return item.Length;
default: return null;
}
}
public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new System.NotImplementedException();
}
#endregion
}
}

Resources