I want to bind a class member of an element I added to a collection to DisplayMemberPath. I bound a ObservableCollection to ComboBox.ItemSource and want to show the property name in the combobox's list which is a member of my class AxisBase.
Here is my code:
private ObservableCollection<AxisBase> axis { get; set; }
axis I use to hold elements of the following class
class AxisBase
{
...
public string name { get; set; }
...
}
This is how my xaml looks like
<ComboBox Name="comboBox_AchsenListe" DisplayMemberPath="{Binding ElementName=axis, Path=AxisBase.name}" ItemsSource="{Binding ElementName=_MainWindow, Path=axis}"</ComboBox>
Does anyone know how to bind name to DisplayMemberPath?
change DisplayMemberPath value
DisplayMemberPath="name"
SelectedValuePath="name"
and look at this question
I have created sample application for you
here the xaml
<Window x:Class="ComboBoxSample.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">
<Grid>
<ComboBox
ItemsSource="{Binding Path=AxisBases}"
DisplayMemberPath="Name"
SelectedValuePath="Name"
Height="23" HorizontalAlignment="Left" Margin="200,134,0,0" Name="comboBox1" VerticalAlignment="Top" Width="120" />
</Grid>
here is code behind
using System.Collections.ObjectModel;
using System.Windows;
namespace ComboBoxSample
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
AxisBases = new ObservableCollection<AxisBase>
{
new AxisBase {Name = "Firts"},
new AxisBase {Name = "Second"},
new AxisBase {Name = "Third"}
};
//Set the data context for use binding
DataContext = this;
}
public ObservableCollection<AxisBase> AxisBases { get; set; }
}
public class AxisBase
{
public string Name { get; set; }
}
}
It works OK and binding also in combo box appears 3 items.
Related
I am new to WPF and data binding. So I am trying some things but now encountered a problem that defies everything I find in reference material.
I have a test program with a string TestString1 that is bound to the Text property of a TextBox tbTest1, that works.
And I have an object TestString2 from ClassTestString2 that contains one property Str. And I want to bind Str to the Text property of a TextBox tbTest2. So I use Text="{Binding Path=TestString2.Str}". According to all documentation you can drill down to a property of an object with the normal C# syntax. But it simply doesn't bind, it doesn't show when starting the program and also making changes in tbTest2 are not reflected in TestString2.Str.
When I use this.DataContext = TestString2; and Text="{Binding Path=Str}", it works but than TestString1 is not bound anymore.
I have the following simple piece of XAML:
<Window x:Class="WpfBindingStringOnly.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:WpfBindingStringOnly"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<TextBox
x:Name="tbTest1"
Text="{Binding Path=TestString1}"
HorizontalAlignment="Left" Height="41"
Margin="124,47,0,0" TextWrapping="Wrap"
VerticalAlignment="Top" Width="250"/>
<TextBox
x:Name="tbTest2"
Text="{Binding Path=TestString2.Str}"
HorizontalAlignment="Left" Height="45"
Margin="124,126,0,0" TextWrapping="Wrap"
VerticalAlignment="Top" Width="250"/>
</Grid>
</Window>
And C# code behind:
using System;
using System.Windows;
using static WpfBindingStringOnly.MainWindow;
namespace WpfBindingStringOnly
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public string TestString1 { get; set; }
public class ClassTestString2
{
public string Str { get; set; }
public ClassTestString2(string s)
{
Str = s;
}
}
public ClassTestString2 TestString2;
public MainWindow()
{
TestString1 = "Hello1";
TestString2 = new("Hello2");
InitializeComponent();
this.DataContext = this;
}
}
}
Bindings work on properties, not fields.
Change your TestString2 member from
public ClassTestString2 TestString2; // This is a field.
to
public ClassTestString2 TestString2 { get; set; } // This is a property.
I have some problems with my Custom Control - Two way binding don't work when I use it in template.
So I have created template xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp1"
xmlns:controls="clr-namespace:GUIControls;assembly=GUIControls"
>
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp1"
xmlns:controls="clr-namespace:GUIControls;assembly=GUIControls"
>
<ControlTemplate x:Key="YParamCombo" TargetType="ContentControl">
<controls:ParamCombo Header="MY CONTROL TEMPLATE"
Items="{Binding Items}"
PCValue="{Binding Codes[MY_CONTROL_TEMPLATE], Mode=TwoWay}"
Required="True"
MultiSelect="False"/>
</ControlTemplate>
<ControlTemplate x:Key="YComboBox" TargetType="ContentControl">
<ComboBox DisplayMemberPath="Name"
StaysOpenOnEdit="True"
ItemsSource="{Binding Items}"
SelectedValue="{Binding Codes[STANDARD_TEMPLATE], Mode=TwoWay}"
SelectedValuePath="Code"/>
</ControlTemplate>
MainWindow.xaml
<Window x:Class="WpfApp1.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:WpfApp1"
mc:Ignorable="d"
xmlns:controls="clr-namespace:GUIControls;assembly=GUIControls"
Title="MainWindow" Height="250" Width="525">
<Grid Margin="0,0,0,-1">
<Button Margin="62,162,299,4" Content="Show Codes-1" Click="Button_Click2"></Button>
<StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<HeaderedContentControl Header="STANDARD CONTROL XAML" >
<ComboBox DisplayMemberPath="Name"
StaysOpenOnEdit="True"
ItemsSource="{Binding Items}"
SelectedValue="{Binding Codes[STANDARD_XAML]}"
SelectedValuePath="Code"/>
</HeaderedContentControl>
<HeaderedContentControl Header="STANDARD CONTROL TEMPLATE" >
<ContentControl Height="23" Template="{StaticResource YComboBox}"/>
</HeaderedContentControl>
<ContentControl Height="44" Template="{StaticResource YParamCombo}">
</ContentControl>
<controls:ParamCombo Header="MY CONTROL XAML"
Items="{Binding Items}"
PCValue="{Binding Codes[MYCONTROL_XAML], Mode=TwoWay}"
Required="True"
MultiSelect="False"/>
</StackPanel>
</Grid>
cs
using System.Linq;
using System.Windows;
namespace WpfApp1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
DataContext = new WModel();
InitializeComponent();
}
private WModel vm { get { return (DataContext as WModel); } }
private void Button_Click2(object sender, RoutedEventArgs e)
{
MessageBox.Show(string.Join(";", vm.Codes._codes.Select(x => x.Key + "=" + x.Value).ToArray()));
}
}
}
using GUIControls;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace WpfApp1
{
public class WModel
{
public WModel()
{
Codes = new CodesClass();
}
public string Caption { get; set; }
public ObservableCollection<Dict> Items
{
get
{
return new ObservableCollection<Dict>()
{
new Dict(){ Name = "Name1", Code = "Code1" } ,
new Dict(){ Name = "Name2", Code = "Code2" }
};
}
}
public CodesClass Codes { get; set; }
}
public class Dict : IDict
{
public string Name { get; set; }
public string Code { get; set; }
}
public class CodesClass
{
public Dictionary<string, object> _codes;
public CodesClass()
{
_codes = new Dictionary<string, object>();
}
public object this[string param]
{
get
{
if (_codes.ContainsKey(param))
return _codes[param];
else
return null;// "I have no " + param;
}
set
{
_codes[param] = value;
}
}
}
}
When I run app and select all 4 comboboxes and Press button, I can see that twoway binding in one combobox(Custom Control declared in template ) do not work
---------------------------
---------------------------
STANDARD_XAML=Code2;STANDARD_TEMPLATE=Code2;MYCONTROL_XAML=Code2
---------------------------
ОК
---------------------------
Some code from control
public static readonly DependencyProperty PCValueProperty =
DependencyProperty.Register("PCValue", typeof(string), typeof(ParamCombo),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(OnPCValuePropertyChanged)));
//new PropertyMetadata(new PropertyChangedCallback(OnValuePropertyChanged)));, new PropertyChangedCallback(OnPCValuePropertyChanged))
#endregion
private static void OnPCValuePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
ParamCombo paramCombo = (ParamCombo)sender;
paramCombo.UpdateSelected((e.NewValue == null) ? "" : e.NewValue.ToString());
}
Thanks for your help!
I have had problems with twoway binding in a combo in a customcontrol template and the solution was to override OnApplyTemplate in the custom control, using Template.FindName to get the combo, get the DataContex object of the combo and raise PropertyChanged in the DataContext object for the bound property. My problem was to update the combo when the window was loaded.
I'm trying to bind a property that was defined in Page code-behind to a ListView.DataContext property in XAML, but for some reason it's not working in the way that I thought, when I run the app the ListView.DataContext is not being set and remains null, can someone please help me with that?
I looked for some similar questions but most of them solve the problem by setting the DataContext manually in the code-behind, but I'd like to do that from XAML.
MainPage.xaml
<Page
x:Class="CustomControls.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:CustomControls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel>
<ListView
DataContext="{Binding Path=MyMarket, RelativeSource={RelativeSource Mode=Self}}"
ItemsSource="{Binding Path=Products}"
Header="{Binding Path=Name}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=Id}"/>
<TextBlock Text="{Binding Path=Description}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</Page>
MainPage.xaml.cs
using System.Collections.ObjectModel;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace CustomControls
{
public sealed partial class MainPage : Page
{
public Market MyMarket { get; private set; }
public MainPage()
{
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Required;
this.MyMarket = new Market
{
Name = "My Market",
Products = new ObservableCollection<Product>
{
new Product { Id = 123, Description = "qwerty" },
new Product { Id = 234, Description = "wertyu" }
}
};
}
}
public class Product
{
public int Id { get; set; }
public string Description { get; set; }
}
public class Market
{
public string Name { get; set; }
public ObservableCollection<Product> Products { get; set; }
}
}
You have to bind to the page, so you have to do that at the very top of your XAML:
<Page
[..]
DataContext="{Binding MyMarket, RelativeSource={RelativeSource Self}}">
Then you should be able to hook into that like this:
<ListView
ItemsSource="{Binding Path=Products}"
Header="{Binding Path=Name}">
[..]
Now just switch the lines in your constructor so that your elements are already there before the page is built:
this.MyMarket = new Market
{
Name = "My Market",
Products = new ObservableCollection<Product>
{
new Product { Id = 123, Description = "qwerty" },
new Product { Id = 234, Description = "wertyu" }
}
};
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Required;
You should consider using Viewmodel classes later on.
{RelativeSource Mode=Self} refers to the current element, in this case ListView, so it's not what you want. The easiest way is to give a name to the root element (the Page), for instance "root", and specify ElementName=root in your binding.
I'm having trouble with binding the ItemsSource of a listbox to a collection of objects and then displaying a property of those objects as the list items.
My XAML code:
<Window 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"
mc:Ignorable="d"
x:Class="CaliburnMicroBasic.ShellView"
d:DesignWidth="358" d:DesignHeight="351">
<Grid Width="300" Height="300" Background="LightBlue">
<ListBox ItemsSource="{Binding ListOfPeople}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding PersonName}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
My ViewModel:
namespace CaliburnMicroBasic {
using Caliburn.Micro;
using System.Collections.ObjectModel;
using System.Windows;
public class ShellViewModel : Screen, IShell
{
public Person SelectedPerson{ get; private set; }
public ObservableCollection<Person> ListOfPeople{ get; private set; }
public ShellViewModel()
{
ListOfPeople = new ObservableCollection<Person>();
ListOfPeople.Add(new Person("Name 1"));
ListOfPeople.Add(new Person("Name 2"));
ListOfPeople.Add(new Person("Name 3"));
ListOfPeople.Add(new Person("Name 4"));
}
}
public class Person
{
public string PersonName { get; private set; }
public Person(string personName)
{
_personName = personName;
}
}
}
As you can see, I'm trying to have the listbox use Person.PersonName as the contents of each textblock in the listbox, but all I'm getting is four empty rows in the listbox. In other words, the listbox contains the correct number of items, but none of them are rendered correctly.
Can anyone see what I'm doing wrong?
You are never assigning anything to your PersonName property. Change your code to:
public Person(string personName)
{
this.PersonName = personName;
}
and remove your private field.
I'm learning WPF and investigating DataBinding. I want to see how to specify the DataBinding in XAML rather than in C# but cant figure out what I'm doing wrong in the example below.
(I know there are many questions like this already, but I've gone through them all but cant get any of the suggestions to work).
<Window x:Class="DataBinding2.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"
x:Name="theMainWindow"
xmlns:local="clr-namespace:DataBinding2"
>
<StackPanel>
<WrapPanel Name="WrapPanel1" Orientation="Vertical" Margin="10" >
<!--// Tried this but get error: The type 'local:person2' was not found. -->
<WrapPanel.DataContext>
<local:person2 />
</WrapPanel.DataContext>
<TextBlock Text="{Binding Path=FirstName}"/>
</WrapPanel>
namespace DataBinding2
{
public partial class MainWindow : Window
{
public Person person2;
public MainWindow()
{
person2 = new Person()
{
FirstName = "Bob",
};
InitializeComponent();
// This works - but want to know what alternative is to do it in XAML
//WrapPanel1.DataContext = person2;
}
}
public class Person
{
public string FirstName { get; set; }
public int Age { get; set; }
}
You can set DataContext to only instance and not directly to property within some instance from XAML.
For that to work first make person2 a property since binding only works with properties at least for instance objects:
public Person person2 { get; set; }
and then you can set DataContext in XAML like this:
<WrapPanel Name="WrapPanel1" Orientation="Vertical" Margin="10"
DataContext="{Binding person2, ElementName=theMainWindow}">