I'd like to set a property of a re-defined UserControl (for example its background color) to a property of the class. For example.
If I define the background of a Button to a property (<Button x:Name="myButton" Background="{Binding ColorName}"/>), it works fine. However, if I do the same for a re-defined UserControl (<local:MyUserControl Background="{Binding Path=ColorName}"/>), it does not.
What's funny though, is that, if I do <local:MyUserControl Background="{Binding Background, ElementName=myButton}"/>, it works perfectly fine.
Could I have some help on that? I must be missing something.
Thanks!
EDIT
Here is all the code. The setting of the background color worked fine. What solved this was to set properly the MainWindow.DataContext and to remove the DataContext = this in MyUserControl.xaml.cs. Setting Color as a DependencyProperty is also useful to be able to change the Color setting in a later execution of the code.
Nonetheless, while removing DataContext=this in MyUserControl.xaml.cs,
the {Binding TextContent} does not work and needs to be replaced by {Binding TextContent, RelativeSource={RelativeSource AncestorType=c:MyUserControl}}.
MainWindow.xaml
<Window x:Class="BindingBug.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:BindingBug"
Title="MainWindow" Height="350" Width="525"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Button Background="{Binding Path=Color}"
Width="250"
Height="30"
Content="I am bound to be RED!"
Grid.Row="0"
x:Name="myButton"/>
<c:MyUserControl Background="{Binding Background, ElementName=myButton}"
Width="250"
Height="30"
Content="I am bound to be RED!"
Grid.Row="1"/>
<c:MyUserControl Background="{Binding Path=Color}"
Width="250"
Height="30"
Content="I am bound to be RED!"
Grid.Row="2"/>
</Grid>
</Window>
MainWindow.xaml.cs
using System.Windows;
using System.Windows.Media;
namespace BindingBug
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Color = Brushes.Red;
}
public static readonly DependencyProperty ColorProperty = DependencyProperty.Register("Color", typeof(Brush), typeof(MainWindow));
public Brush Color
{
get
{
return (Brush)GetValue(ColorProperty);
}
set
{
SetValue(ColorProperty, value);
}
}
}
}
MyUserControl.xaml
<UserControl x:Class="BindingBug.MyUserControl"
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:c="clr-namespace:BindingBug"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="2*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0"
FontSize="13"
Text="{Binding TextContent, RelativeSource={RelativeSource AncestorType=c:MyUserControl}}"
VerticalAlignment="Center"/>
</Grid>
</UserControl>
MyUserControl.xaml.cs
using System.Windows;
using System.Windows.Controls;
namespace BindingBug
{
/// <summary>
/// Interaction logic for NumberDataHolder.xaml
/// </summary>
public partial class MyUserControl : UserControl
{
public MyUserControl()
{
InitializeComponent();
}
public static readonly DependencyProperty TextContentProperty = DependencyProperty.Register("TextContent", typeof(string), typeof(MyUserControl));
public string TextContent
{
get
{
return (string)GetValue(TextContentProperty);
}
set
{
SetValue(TextContentProperty, value);
}
}
}
}
EDIT 2
I tried to acheive the same results without having to declare the whole Text="{Binding TextContent, RelativeSource={RelativeSource AncestorType=c:MyUserControl}}" inside TextBlock. So, following #KeithStein advice, I placed DataContext="{Binding RelativeSource={RelativeSource Self}}" inside MyUserControl and only kept Text="{Binding TextContent}"inside TextBlock. That, however cancels the effect of setting Background="{Binding Path=Color}" in MainWindow.xaml. Any idea why? Is there another possibility to set Background="{Binding Path=Color}" in MainWindow.xaml and to only keepText="{Binding TextContent}"inside TextBlock?
MainWindow.xaml
<Window x:Class="BindingBug.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:BindingBug"
Title="MainWindow" Height="350" Width="525"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Button Background="{Binding Path=Color}"
Width="250"
Height="30"
Content="I am bound to be RED!"
Grid.Row="0"
x:Name="myButton"/>
<c:MyUserControl Background="{Binding Background, ElementName=myButton}"
Width="250"
Height="30"
Content="I am bound to be RED!"
Grid.Row="1"/>
<c:MyUserControl Background="{Binding Path=Color}"
Width="250"
Height="30"
Content="I am bound to be RED!"
Grid.Row="2"/>
</Grid>
</Window>
MainWindow.xaml.cs
using System.Windows;
using System.Windows.Media;
namespace BindingBug
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Color = Brushes.Red;
}
public static readonly DependencyProperty ColorProperty = DependencyProperty.Register("Color", typeof(Brush), typeof(MainWindow));
public Brush Color
{
get
{
return (Brush)GetValue(ColorProperty);
}
set
{
SetValue(ColorProperty, value);
}
}
}
}
MyUserControl.xaml
<UserControl x:Class="BindingBug.MyUserControl"
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:c="clr-namespace:BindingBug"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="2*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0"
FontSize="13"
Text="{Binding TextContent}"
VerticalAlignment="Center"/>
</Grid>
</UserControl>
MyUserControl.xaml.cs
using System.Windows;
using System.Windows.Controls;
namespace BindingBug
{
/// <summary>
/// Interaction logic for NumberDataHolder.xaml
/// </summary>
public partial class MyUserControl : UserControl
{
public MyUserControl()
{
InitializeComponent();
}
public static readonly DependencyProperty TextContentProperty = DependencyProperty.Register("TextContent", typeof(string), typeof(MyUserControl));
public string TextContent
{
get
{
return (string)GetValue(TextContentProperty);
}
set
{
SetValue(TextContentProperty, value);
}
}
}
}
This answer developed gradually through back and forth comments with OP. To summarize:
Use a Brush-type dependency property for your color. Brush because that is the type of the Background property that you want to bind to, and a dependency property so that updates of the property trigger any bindings to refresh.
When binding inside a Window or UserControl, you need to set DataContext, which is essentially the default sourced used by bindings.
For a Window, add DataContext="{Binding RelativeSource={RelativeSource Self}}" to the opening tag. This sets the default source for all controls contained within to the Window itself.
For a UserControl, add the following to the outer-most panel of said control: DataContext={Binding RelativeSource={RelativeSource AncestorType=UserControl}} (UserControl can be replaced with the name of your particular control, i.e. c:MyUserControl). This tells everything inside that root panel to use the UserControl as the default source. You can't use RelativeSource Self in this case, because then instances of the MyUserControl will bind to themselves when placed inside Windows, instead of inheriting the Window's DataContext.
Related
I'm using MVVM Light in my WPF application.
I created a class RedirectToUriCommandArgument.cs.
public class RedirectToUriCommandArgument : DependencyObject
{
#region Properties
public static readonly DependencyProperty PageProperty =
DependencyProperty.Register(nameof(Page), typeof(object), typeof(RedirectToUriCommandArgument), new UIPropertyMetadata(null));
public object Page
{
get => (object)GetValue(PageProperty);
set => SetValue(PageProperty, value);
}
public string Uri { get; set; }
#endregion
#region Methods
#endregion
}
In .xaml file, I used:
<Window x:Class="MainClient.Views.AppView"
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:v="clr-namespace:MainClient.Views"
xmlns:vm="clr-namespace:MainClient.ViewModel"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:commandArgument="clr-namespace:MainClient.Models.CommandArguments"
xmlns:local="clr-namespace:MainClient"
mc:Ignorable="d"
WindowStartupLocation="CenterScreen"
Height="350" Width="525">
<Window.DataContext>
<vm:AppViewModel x:Name="AppContext"></vm:AppViewModel>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="32"/>
</Grid.RowDefinitions>
<Frame NavigationUIVisibility="Hidden" x:Name="PageFrame">
<Frame.Content>
<Page Name="MainPage"></Page>
</Frame.Content>
</Frame>
<StackPanel Grid.Row="1" Orientation="Horizontal">
<Button>
<Button.Content>
<TextBlock>Redirect to main view</TextBlock>
</Button.Content>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding RedirectToViewRelayCommand}">
<i:InvokeCommandAction.CommandParameter>
<commandArgument:RedirectToUriCommandArgument Page="{Binding ElementName=PageFrame}" Uri="MainView.xaml"></commandArgument:RedirectToUriCommandArgument>
</i:InvokeCommandAction.CommandParameter>
</i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</StackPanel>
</Grid>
</Window>
The Page property is always null.
Am I missing anything ?
So I think the problem is, that as binding been initialized the UIElement is not created(null). Afterwords the binding is not notified, that the object is created.
Binding to the properties is easyer the object must implement INotifyPropertyChanged or DependencyObject take care about dependency properties.
To solve your issue you could set a Delay for Binding, say to 1000ms, then it will work. It's doubtful whether it is a right way.
<commandArgument:RedirectToUriCommandArgument Page="{Binding ElementName=PageFrame, Delay=1000}" Uri="MainView.xaml"></commandArgument:RedirectToUriCommandArgument>
The right way would be just set binding's source to the UIElement:
<commandArgument:RedirectToUriCommandArgument Page="{Binding Source={x:reference PageFrame}}" Uri="MainView.xaml"></commandArgument:RedirectToUriCommandArgument>
This is my first question on stackoverflow.
I have a Usercontrol that contains a viewModel as a staticresource. Than I have a Window that contains this UserModel. I want to send commands from the Window to the viewmodel that is used by the usercontrol. So I bound the Viewmodel class to the Usercontrol and to the Window as a static Resource. But the viewmodell ist instanciated 2 times. Once from the Window and once from the usercontrol. What am I doing wrong?
Here is the xaml of the usercontrol:
<UserControl x:Class="ScanVM.ScanView"
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:t="clr-namespace:ScanVM"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="501.305">
<UserControl.Resources>
<t:ScanVM x:Key="ABC"/>
</UserControl.Resources>
<DockPanel DataContext="{Binding Source={StaticResource ABC}}">
<Grid ShowGridLines="True" Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="5*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="10*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Label Content="Geräte:" Grid.Column="0" Grid.Row="1" HorizontalAlignment="Right" Margin="0,10,10,0"/>
<DataGrid ItemsSource="{Binding Path=ScanIDs, Mode=OneWay}" Grid.Column="1" HorizontalAlignment="Left" Margin="10,10,0,0" Grid.Row="1" VerticalAlignment="Top" AutoGenerateColumns="false" Height="152" >
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding ScanIds}" ClipboardContentBinding="{x:Null}" Header="Bezeichnung" MinWidth="200"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</DockPanel>
This is the code of my window:
<Window x:Class="ScanViewer.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:ribbon="clr-namespace:System.Windows.Controls.Ribbon;assembly=System.Windows.Controls.Ribbon"
xmlns:self="clr-namespace:ScanViewer"
xmlns:t="clr-namespace:ScanVM;assembly=ScanVM"
mc:Ignorable="d"
Title="Scan-Viewer" Height="682.225" Width="694">
<Window.Resources>
<t:ScanVM x:Key="ABC"/>
</Window.Resources>
<Window.CommandBindings>
<CommandBinding
Command="self:MainWindow.ExitCommand"
CanExecute="ExitCommand_CanExecute"
Executed="ExitCommand_Execute"/>
</Window.CommandBindings>
<DockPanel>
<ribbon:Ribbon DockPanel.Dock="Top">
<Ribbon.ApplicationMenu>
<RibbonApplicationMenu Visibility="Collapsed">
<RibbonApplicationMenuItem Header="Beenden"/>
<RibbonApplicationMenu.FooterPaneContent>
<RibbonButton Label="Exit"/>
</RibbonApplicationMenu.FooterPaneContent>
</RibbonApplicationMenu>
</Ribbon.ApplicationMenu>
<RibbonTab Header="Start">
<RibbonGroup Header="Programm">
<RibbonButton Label="Beenden" Margin="0,5,0,0" Command="self:MainWindow.ExitCommand" />
</RibbonGroup>
<RibbonGroup Header="Scannen">
<RibbonButton Label="Daten Scannen" Margin="0,5,0,0" Command="{Binding ScanCmd, Source={StaticResource ABC}}"/>
</RibbonGroup>
</RibbonTab>
</ribbon:Ribbon>
<Grid DockPanel.Dock="Top" Height="464">
<t:ScanView DataContext="{Binding Source={StaticResource ABC}}"/>
</Grid>
</DockPanel>
And this is the code of my Viewmodel:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Windows.Input;
using System.Threading;
using MVVMBase;
namespace ScanVM
{
public class ScanVM : ViewModelBase
{
private ICommand _doWorkCmd;
private ICommand _scanCmd;
private bool scanAllowed = false;
public List<int> ScanIDs
{
get;
set;
}
public ScanVM()
{
_doWorkCmd = new DelegateCommand((param) => DoWork());
_scanCmd = new DelegateCommand((param) => Scan());
}
public bool NWScanAllowed(object executeAllowed)
{
return scanAllowed;
}
public ICommand WorkCmd
{
get { return _doWorkCmd; }
}
public ICommand ScanCmd
{
get
{
return _scanCmd;
}
}
private void Scan()
{
scanAllowed = true;
}
private void DoWork()
{
}
}
}
The answer depends on what you want to do with the shared object.
You can either move ABC to App.xaml inside <Application.Resources> tag to share it throughout your project.
Or you can remove the one in user control and use the ABC in window's resources.
You will need a valid reference path to address the ABC in window resource from user control in this case.
which brings us to these two situations:
The valid path is possible to find:
So let's say if your user control is a part of the mentioned window (and if the window's DataContext is set to ABC) then inside the user control you will reference it like this:
<DockPanel DataContext="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=DataContext}">
The valid path is impossible to find and you just want the static resource. If you insist on doing it this way it is better to just move the resource to App.xaml than to try to tweak this out.
I try to figure out how MVVM works and want to start simple.
I made a Model, a View and a ViewModel. I hooked up the view to a window. this works more or less.
in the view i have a textbox which i want to fill with the value of a property. The textbox keeps empty!?
This is what i have:
Model:
namespace Qbox_0001.Model
{
public class RegistratieModel
{
}
public class Registratie : INotifyPropertyChanged
{
//Fields
private string programmaNaam;
//eventhandler die kijkt of een property wijzigt
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
//Properies
public string ProgrammaNaam
{
get { return programmaNaam; }
set
{
if (programmaNaam != value)
{
programmaNaam = value;
RaisePropertyChanged("ProgrammaNaam");
}
}
}
}
}
The View:
<UserControl x:Name="UserControlRegistratie" x:Class="Qbox_0001.Views.RegistratieView"
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:Qbox_0001.Views"
mc:Ignorable="d" Height="1000" Width="860" MaxWidth="860" HorizontalContentAlignment="Left" VerticalContentAlignment="Top">
<Grid x:Name="GridRegistratie">
<Grid.RowDefinitions>
<RowDefinition x:Name="RowDef_Menu" Height="21*" MaxHeight="21" MinHeight="21"/>
<RowDefinition x:Name="RowDef_TabControl" Height="500*" MinHeight="500"/>
<RowDefinition x:Name="Rowdef_Bottom" Height="40*" MaxHeight="40" MinHeight="40"/>
</Grid.RowDefinitions>
<Grid x:Name="Grid_Registratie_WorkArea" Grid.Row="1">
<TabControl x:Name="TabControl_Registratie">
<TabItem Header="Registratie">
<Grid x:Name="Grid_Tab_Registratie">
<Border>
<Grid>
<Grid.RowDefinitions>
<RowDefinition x:Name="GridRowDef_Algemeen" MinHeight="68" Height="68*" MaxHeight="68"/>
<RowDefinition x:Name="GridRowDef_Locatie" MinHeight="120" Height="120*" MaxHeight="120"/>
<RowDefinition x:Name="GridRowDef_AantalDagen" MinHeight="105" Height="105*" MaxHeight="105"/>
<RowDefinition x:Name="GridRowDef_MaxDagen" MinHeight="105" Height="105*" MaxHeight="105"/>
<RowDefinition x:Name="GridRowDef_Lokaal" MinHeight="100" Height="100*" MaxHeight="100"/>
<RowDefinition x:Name="GridRowDef_LicBestand" Height="150*" MaxHeight="150" MinHeight="150"/>
</Grid.RowDefinitions>
<GroupBox x:Name="GroupBox_algemeen" Header="Algemeen" Margin="10,4,10,3">
<Grid>
<Label x:Name="Label_Klant" Content="Klant:" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Padding="0,5,5,5"/>
<Label x:Name="Label_Programma" Content="Programma:" HorizontalAlignment="Left" Margin="356,10,0,0" VerticalAlignment="Top"/>
<Label x:Name="Label_Versie" Content="Versie:" HorizontalAlignment="Left" Margin="645,10,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="textBox_KlantNaam" HorizontalAlignment="Left" Height="23" Margin="49,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="288"/>
<!-- the textbox keeps empty -->
<TextBox x:Name="TextBox_ProgrammaNaam" Text="{Binding ElementName=RegistratieViewModel, Path=ProgrammaNaam, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Height="23" Margin="431,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="190" IsEnabled="False" />
<TextBox x:Name="TextBox_Versie" HorizontalAlignment="Left" Height="23" Margin="695,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" IsEnabled="False" />
</Grid>
</GroupBox>
</Grid>
</Border>
</Grid>
</TabItem>
<TabItem Header="Licentie(s)">
<Grid x:Name="Grid_Tab_Licentie" Background="#FFE5E5E5"/>
</TabItem>
</TabControl>
</Grid>
</Grid>
</UserControl>
In the View.cs:
namespace Qbox_0001.Views
{
/// <summary>
/// Interaction logic for RegistratieView.xaml
/// </summary>
public partial class RegistratieView : UserControl
{
public RegistratieView()
{
InitializeComponent();
this.DataContext = new Qbox_0001.ViewModel.RegistratieViewModel();
}
}
}
The ViewModel
using Qbox_0001.Model; //
using System.Collections.ObjectModel; //
namespace Qbox_0001.ViewModel
{
public class RegistratieViewModel
{
public RegistratieViewModel()
{
loadRegistratieOnderdelen();
}
public ObservableCollection<Registratie> RegistratieOnderdelen //Registratie = "public class Registratie : INotifyPropertyChanged" van de Model
{
get;
set;
}
public void loadRegistratieOnderdelen()
{
ObservableCollection<Registratie> regOnderdelen = new ObservableCollection<Registratie>();
regOnderdelen.Add(new Registratie { ProgrammaNaam = "Test" });
}
}
}
I can see a couple of problems with your code.
You are populating a local ObservableCollection (inside your loadRegistratieOnderdelen() method) with data but since its local, it is not a member of the DataContext and hence unavailable to the View. You have to use public properties like RegistratieOnderdelen which you already declared in your RegistratieViewModel.
Next you are using an ObservableCollection whereas you might just want to use a property of type String. Collections are used when you want to represent lists, for example inside a ListView or an ItemsControl. Your view indicates that you want to bind a single text value so a public property of type String makes more sense.
Best, Nico
The DataContext is a RegistratieViewModel. This class has a RegistratieOnderdelen property that returns a collection of Registratie objects.
You could bind to the ProgrammaNaam property of one such item but you need to specify which item to bind to, for example the first one:
<TextBox x:Name="TextBox_ProgrammaNaam" Text="{Binding Path=RegistratieOnderdelen[0].ProgrammaNaam, UpdateSourceTrigger=PropertyChanged}" ... />
When I run the app, I expect to see 5 buttons (see ItemsControl\DataTemplate\Button in my XAML below) each with a content like "55/42" denoting max ad min temperature. However, the window is blank. I know this has to do with ItemsControl because I can display the data without using the ItemsControl. Can someone catch my mistake?
<Window x:Class="Embed_WeatherSummaryAsItemsControl_ToMain.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
FocusManager.FocusedElement="{Binding ElementName=InputCity}"
Title="Weather App" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<TextBox x:Name="InputCity" Grid.Row="0" Width="200" Text="{Binding CityAndOptionalCountry}"></TextBox>
<Button Grid.Row="0" Width="50" Content="Go" Margin="260,0,0,0" Command="{Binding GetWeatherReportCommand}"></Button>
<ItemsControl Grid.Row="1" ItemsSource="{Binding WeatherForecastSummaryCollection}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Path=MaxMinTemperature}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
As shown below, "WeatherForecastSummaryCollection" is a collection property on ViewModel class and "MaxMinTemperature" is a property of item in collection.
public class MainWindowViewModel : ViewModelBase
{
....
private List<WeatherForecastSummary> mWeatherForecastSummaryCollection;
public List<WeatherForecastSummary> WeatherForecastSummaryCollection
{
get { return mWeatherForecastSummaryCollection; }
set
{
mWeatherForecastSummaryCollection = value;
OnPropertyChanged("WeatherForecastSummaryCollection");
}
}
.....
}
public class WeatherForecastSummary
{
public string MaxMinTemperature { get; set; }
}
Thanks for helping!
I think you are missing the DataContext here.
Even if you are using the codebehind of the View, you need to write
this.DataContext = this;
or if you are using someother class as viewmodel you might want to point the datacontext to that class. Just replace "this" in the above code with your viewmodels object.
In this case it would be ,
this.DataContext = new MainWindowViewModel();
I have a custom control that has two listViews employing GridViewRowPresenters. I need the row heights of the two listViews to be the same. The catch is I wont know what the heights will be until run time.
That is, both will have their heights set to Auto and when the control is rendered one listView will have its rows at ActualHeight = 30 the other at ActualHeight = 40. I want them both to be 40.
If the ListViews use a shared item template, all you would have to do is wrap your GridViewRowPresenter in a grid and then use a SharedSizeGroup on that grid's only row. Here's how it can be achieved.
XAML
<UserControl x:Class="WpfApplication1.UserControl2"
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"
d:DesignHeight="300"
d:DesignWidth="300"
mc:Ignorable="d">
<UserControl.Resources>
<GridViewColumnCollection x:Key="GridViewColumns">
<GridViewColumn Width="100"
DisplayMemberBinding="{Binding Path=Text}"
Header="Text" />
</GridViewColumnCollection>
<DataTemplate x:Key="RowTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" SharedSizeGroup="RowSizeGroup" />
</Grid.RowDefinitions>
<Border BorderBrush="Black" BorderThickness="1">
<GridViewRowPresenter Columns="{StaticResource GridViewColumns}" />
</Border>
</Grid>
</DataTemplate>
</UserControl.Resources>
<Grid IsSharedSizeScope="True">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<GridViewHeaderRowPresenter Columns="{StaticResource GridViewColumns}" />
<ListView Grid.Row="1"
ItemTemplate="{StaticResource RowTemplate}"
ItemsSource="{Binding Path=Items1}" />
<ListView Grid.Row="2"
ItemTemplate="{StaticResource RowTemplate}"
ItemsSource="{Binding Path=Items2}" />
</Grid>
</UserControl>
Code-Behind (for reference, but not really important)
using System.Collections.ObjectModel;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for UserControl2.xaml
/// </summary>
public partial class UserControl2
{
public UserControl2()
{
InitializeComponent();
DataContext = this;
Items1 = new ObservableCollection<object>
{
new Item {Text = "Hello World!"},
new Item {Text = "Hello \nWorld!"}
};
Items2 = new ObservableCollection<object>
{
new Item {Text = "Testing 1\n2\n3"}
};
}
private class Item
{
public string Text { get; set; }
}
public ObservableCollection<object> Items1 { get; private set; }
public ObservableCollection<object> Items2 { get; private set; }
}
}
If you want to set the height of your rows explicitly, just replace <RowDefinition Height="Auto" SharedSizeGroup="RowSizeGroup" /> with <RowDefinition Height="40" SharedSizeGroup="RowSizeGroup" /> where 40 in this case is the specific height.