Bidning with TextBlock is not Working - wpf

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>

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>

Binding different properties to different sources

I have a Window with a ListBox which has a DataTemplate, bound to an ObservableCollection of LogItems. The ItemsSource of the ListBox is set in code to the collection; the bindings on the TextBox and TextBlock which make up the DataTemplate are set in XAML. So far, so conventional. However, I need to set the font size/family for the TextBlock at runtime. Currently this information is held in a static cGlobals class. So I need to be able to bind the TextBlock.Text to the LogItems collection, but the TextBlock.FontSize property to the cGlobals.LogFontSize property. How can I do this, either via binding as sketched out in the XAML below, or in code?
<ListBox . . . . >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch" . . . . >
<Grid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition Height="*" MinHeight="40" />
</Grid.RowDefinitions>
<TextBox Grid.Row="0" Background="Honeydew" Text="{Binding Mode=OneWay, Path=Header, . . . . />
<TextBlock FontSize="{Binding ??????}" Grid.Row="1" Text="{Binding Path=BodyText}" />
</Grid>
</DataTemplate >
</ListBox.ItemTemplate >
</ListBox>
xaml
<Window x:Class="WpfApplication6.StaticBinding"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication6"
Title="StaticBinding" Height="300" Width="300">
<Grid>
<TextBlock FontSize="{Binding Source={x:Static local:Global.FontSize}}" Text="abc"/>
</Grid>
Global
public class Global
{
public static double FontSize
{
get { return 20.0; }
}
}
You will need to declare a public property of Type cGlobals but the class cannot be static because you will need to use it as a return type. It does not look like you are following the Model-View-ViewModel pattern, since you are assigning the ItemsSource in the code-behind instead of XAML, so you will need to declare the property in the code-behind. In your Code-Behind(your .xaml.cs file)
private CGlobals _cGlobals;
public CGlobals CGlobals{get{return _cGlobals;}}
public CodeBehindConstructor(){
_cGlobals = new CGlobal{FontSize = 12, FontFamily="Times New Roman"};
}
xaml:
<Window Name="TheWindow">
<TextBlock FontSize="{Binding CGlobals.FontSize, ElementName=TheWindow}" Grid.Row="1" Text="{Binding Path=BodyText}" />
</Window>

Silverlight PropertyGrid-like binding

I know that there are 3rd party silverlight property grids (in fact my company owns one) so please dont suggest 3rd party controls : I am trying to learn more about binding in xaml with this question.
I am writing a Silverlight front end as a sign facade to launch SSRS, and php based reports.
I have created a Report class with information about the report, and it has a parameters collection containing the information about parameters that need to be filled in to run the report.
My plan is to create a silverlight property grid that is bound to the Parameters collection of the Report.
Here's a simpler version of the classes:
public class Report
{
public int ReportId { get; set; }
public string ReportName { get; set; }
public string Description { get; set; }
private List<ReportParameter> _Parameters = new List<ReportParameter>();
public List<ReportParameter> Parameters
{
get { return _Parameters; }
set { _Parameters = value; }
}
}
public class ReportParameter
{
public int ReportId { get; set; }
public string ParameterName { get; set; }
public string DataTemplateName { get; set; }
public bool IsRequired { get; set; }
}
I was hoping to use the DataTemplateName property of ReportParameter to bind to data templates: for example if I have a parameter that is a date, I want to be able to set DataTemplateName="MyDatePicker" and then DataTemplate={StaticResource {Binding DataTemplateName}} and have that row use a DataTemplate defined in the Resources for editing the parameter value.
Here's some XAML I am using to try to get it to work:
<UserControl x:Class="ReportLauncherWorkbench.MainPage"
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:ReportLauncherWorkbench"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<UserControl.Resources>
<local:Report x:Key="MyData"
ReportName="Rick Report"
Description="Great report, try it!"
ReportId="0"
>
<local:Report.Parameters>
<local:XReportParameter DataTemplateName="DatePickerTemplate"
ParameterName="StartDate"
IsRequired="True"
Tooltip="Please enter the start date"
/>
<local:XReportParameter DataTemplateName="CheckBoxTemplate"
ParameterName="AmIHot"
IsRequired="True"
Tooltip="Please check here if you are hot"
/>
</local:Report.Parameters>
</local:Report>
<DataTemplate x:Key="DatePickerTemplate">
<StackPanel Orientation="Horizontal">
<TextBox />
<Button Content="..."/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="CheckBoxTemplate">
<StackPanel Orientation="Horizontal">
<CheckBox/>
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White" DataContext="{StaticResource MyData}">
<Grid x:Name="Test1" Background="White">
<StackPanel>
<TextBlock Text="{Binding ReportName}"/>
<TextBlock Text="{Binding Description}"/>
<ListBox ItemsSource="{Binding Parameters}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding ParameterName}" Grid.Column="1" Margin="5"/>
<ListBox ItemsSource="{Binding}" Grid.Column="2" Width="100" ItemTemplate="{StaticResource {Binding DataTemplateName}}">
<!-- I want to somehow bind which DataTemplate is rendered-->
</ListBox>
</Grid>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</Grid>
</Grid>
</UserControl>
Thanks!
I figured it out - with the help of a great FAQ on the silverlight forum:
http://forums.silverlight.net/p/95440/218611.aspx
Silverlight does not have the DataTemplateSelector class that WPF does, which would have solved the problem.
In section titled
7.1 What data binding features of WPF are not yet supported in Silverlight? Is there a workaround?
There is a simple workaround that for DataTemplateSelector functionality.
So here's how I fixed it in my code sample:
Replace the Listbox with the following:
<ListBox ItemsSource="{Binding Parameters}">
<ListBox.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding}" Loaded="ContentControl_Loaded"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And then fill in the ContentControl_Loaded event in the code behind with:
private void ContentControl_Loaded(object sender, RoutedEventArgs e)
{
ContentControl cc = (ContentControl) sender;
XReportParameter p = (XReportParameter)cc.DataContext;
cc.ContentTemplate = (DataTemplate)this.Resources[p.DataTemplateName];
}
Works great!

Silverlight MVVM - How Can I Declaratively Bind a ComboBox in a DataGrid CellEditingTemplate using a ViewModel?

I am trying to declaratively bind a ComboBox within a DataGrid CellEditingTemplate using a ViewModel. The ComboBox is not being bound. What am I doing wrong?
XAML:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing"
xmlns:data="clr-namespace:SilverlightApplication1"
mc:Ignorable="d"
x:Class="SilverlightApplication1.EmployeeDetail"
Width="640" Height="480">
<UserControl.Resources>
<data:EmployeeDetailsViewModel
x:Key="ViewModel"
d:IsDataSource="True" />
</UserControl.Resources>
<Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource ViewModel}}" Background="White">
<sdk:DataGrid ItemsSource="{Binding Employees,Mode=TwoWay}" AutoGenerateColumns="False" CanUserSortColumns="True" CanUserReorderColumns="True" CanUserResizeColumns="True" GridLinesVisibility="All" Height="317" HorizontalAlignment="Left" Margin="12,136,0,0" Name="EmployeesGrid" VerticalAlignment="Top" Width="605">
<sdk:DataGrid.Columns>
<!-- snipped from brevity -->
<sdk:DataGridTemplateColumn Header="Status">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding EmployeeStatus.Description}" TextWrapping="Wrap"></TextBlock>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
<sdk:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Path=EmployeeStatuses}" SelectedItem="{Binding EmployeeStatus, Mode=TwoWay}" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellEditingTemplate>
</sdk:DataGridTemplateColumn>
</sdk:DataGrid.Columns>
</sdk:DataGrid>
<TextBlock x:Name="SearchLabel" HorizontalAlignment="Left" Margin="12,95,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="106" Height="34"><Run FontWeight="Bold" Text="Search By Name: "/><Run FontSize="9.333" Text="(Last, First)"/></TextBlock>
<TextBox x:Name="SearchParam" HorizontalAlignment="Left" Margin="144,101,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="162"/>
<Button x:Name="SearchButton" Content="Search" HorizontalAlignment="Right" Margin="0,102,242,0" VerticalAlignment="Top" Width="75" Click="SearchButton_Click"/>
</Grid>
</UserControl>
VIEW MODEL:
using System.Collections.ObjectModel;
using SilverlightApplication1.EmployeeService;
using SilverlightApplication1.ViewModels;
namespace SilverlightApplication1
{
public class EmployeeDetailsViewModel : ViewModelBase
{
readonly IEmployeeServiceAgent _serviceAgent;
ObservableCollection<EmployeeStatus> _employeeStatuses { get; set; }
ObservableCollection<Employee> _employees { get; set; }
public EmployeeDetailsViewModel() : this(new EmployeeServiceAgent()) { }
public EmployeeDetailsViewModel(IEmployeeServiceAgent serviceAgent)
{
if (!IsDesignTime)
{
_serviceAgent = serviceAgent;
GetAllEmployees();
GetEmployeeStatuses();
}
}
public ObservableCollection<Employee> Employees
{
get { return _employees; }
set
{
if(_employees!=value)
{
_employees = value;
OnNotifyPropertyChanged("Employees");
}
}
}
public ObservableCollection<EmployeeStatus> EmployeeStatuses
{
get { return _employeeStatuses; }
set
{
if (_employeeStatuses != value)
{
_employeeStatuses = value;
OnNotifyPropertyChanged("EmployeeStatuses");
}
}
}
private void GetAllEmployees()
{
_serviceAgent.GetAll((s, e) => Employees = e.Result);
}
private void GetEmployeeStatuses()
{
_serviceAgent.GetEmployeeStatuses((s, e) => EmployeeStatuses = e.Result);
}
}
}
Update:
This seems wrong but I figured out how to get the binding working by re-referencing the ViewModel in the ItemSource Binding:
<ComboBox ItemsSource="{Binding Source={StaticResource ViewModel},Path=EmployeeStatuses}"
DisplayMemberPath="Description"
SelectedItem="{Binding EmployeeStatus, Mode=TwoWay}" />
However, a am now experiencing a problem where the SelectedItem is not bound! What am I doing wrong?
The problem is a common one that people run into. When you're in the data template of the column, you're no longer bound the the view model. At that point your data context is the EmployeeStatus object (which doesn't have an EmployeeStatuses property to bind to).
So to get the combobox binding to work you can use the ElementName=LayoutRoot to bind back up the tree to the root ViewModel.
Update: Here would be the full syntax for your binding:
{Binding DataContext.EmployeeStatuses, ElementName=LayoutRoot}
Update2: I've actually run into this as well and there is a workaround you have to implement to get the element name binding to work inside a datagrid.
If Bryant's solution does not work (in SL4), use static resources. See this link: http://blog.digitaltools.com/post/2011/05/06/Binding-a-Datagride28099s-ComboBox.aspx
Or, by creating the static resource in xaml: http://forums.silverlight.net/post/370135.aspx

WPF binding user control with data in C# code

I've create user control like this:
public partial class View
{
public View()
{
InitializeComponent();
}
public static DependencyProperty NameProperty = DependencyProperty.Register("Name", typeof(string), typeof(TeaserView) );
public string Name
{
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
}
XAML:
<UserControl x:Class="Controls.View"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="200" Width="164">
<Grid VerticalAlignment="Stretch"
x:Name="Preview">
<Label Height="28" Content="{Binding ElementName=Preview, Path=Name}" Background="LightYellow" x:Name="name" VerticalAlignment="Top" ></Label>
</Grid>
</UserControl>
and use it in Window1 simply in XAML:
<controls:View Height="200" Name="View1" Width="164" />
and I try set the Content in C# (Name property in this sample) but it does'n work, label's content is still empty. (All refereces, etc. are good) What's wrong?
Your code is wrong. You bind to Grid.Name property, which is "Preview", not to View.Name.
I really encourage you to go read from A to Z "DataBinding Overview" on MSDN. It worth your time, trust me :). In fact whole "Windows Presentation Foundation" section would be worth your attention.
As for your code, the following will work:
<UserControl x:Class="WpfApplication5.View"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300"
Width="300"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<Label Height="28"
Content="{Binding Path=Name}"
Background="LightYellow"
VerticalAlignment="Top"/>
</Grid>
</UserControl>
But are you sure you want to hide "Name" property from parents?
Have you set the datacontext on the user control? Try setting it to point to its own codebehind:
DataContext="{Binding RelativeSource={RelativeSource Self}}"
I've put the Name property just as sample. I'm trying to set Label Content in Window1.xaml.cs like:
View1.Name = "Casablanca";
Try the following binding, it should work:
<Label Content="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:View}}, Path=Name}" />
You should also define a xmlns:local="whatever_path_you_have" on the top of the file.
I also suggest renaming "Name" DP to something else to avoid name collusion.
Copied your exact code and it works fine.
However, it's not doing what you're probably expecting it to do. You're setting the source of the binding to the Grid instance. Therefore, the Name property will yield "Preview". The Name property you've defined in your UserControl is ignored because there's already a Name property on UserControl.

Resources