I have a serious problem on binding value to property.
This is my source code.
public partial class MainPage : Page,Autodesk.Revit.UI.IDockablePaneProvider
{
....
public System.Windows.Media.Brush BCol { get; set; }
.....
}
<ListBox Style = "{DynamicResource ListBoxStyle}">
...
</ListBox>
<Style x:Key="ListBoxStyle" TargetType="{x:Type ListBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}">
<Grid Background="{Binding BCol}">
...
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I want to bind BCol to grid background but it doesn't work.
How should I do?
Depending on where BCol is set, you might need to implement INotifyPropertyChanged interface. You also need to make sure that you are binding to the view model that is assigned to your DataContext.
You can also create a DependencyProperty. I have posted both solutions below. DependencyProperty one is probably the solution that you want.
INotifyPropertyChanged solution:
XAML
<Page x:Class="WpfTest.MainPage"
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:WpfTest"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Title="MainPage">
<Grid>
<Grid.Resources>
<Style x:Key="ListBoxStyle" TargetType="{x:Type ListBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}">
<Grid Background="{Binding BCol}">
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<ListBox Style = "{DynamicResource ListBoxStyle}">
</ListBox>
</Grid>
</Page>
Code behind:
using System.ComponentModel;
using System.Windows.Controls;
using System.Windows.Media;
namespace WpfTest
{
/// <summary>
/// Interaction logic for MainPage.xaml
/// </summary>
public partial class MainPage : Page, INotifyPropertyChanged
{
private Brush bCol;
public System.Windows.Media.Brush BCol
{
get { return bCol; }
set
{
bCol = value;
RaisePropertyChanged("BCol");
}
}
public MainPage()
{
InitializeComponent();
DataContext = this; //This is a hack, you should really create a separate view model
BCol=new SolidColorBrush(Colors.Blue);
}
public event PropertyChangedEventHandler PropertyChanged= delegate { };
void RaisePropertyChanged(string name)
{
PropertyChanged(this,new PropertyChangedEventArgs(name));
}
}
}
DependencyProperty solution
XAML
<Page x:Class="WpfTest.MainPage"
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:WpfTest"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Title="MainPage">
<Grid>
<Grid.Resources>
<Style x:Key="ListBoxStyle" TargetType="{x:Type ListBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}">
<Grid Background="{Binding RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type local:MainPage}}, Path=BCol}">
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<ListBox Style = "{DynamicResource ListBoxStyle}">
</ListBox>
</Grid>
</Page>
Code behind
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace WpfTest
{
/// <summary>
/// Interaction logic for MainPage.xaml
/// </summary>
public partial class MainPage : Page
{
private Brush bCol;
public static DependencyProperty BColProperty =DependencyProperty.Register("BCol", typeof(Brush),typeof(MainPage));
public Brush BCol
{
get { return (Brush)this.GetValue(BColProperty); }
set { this.SetValue(BColProperty, value); }
}
public MainPage()
{
InitializeComponent();
BCol=new SolidColorBrush(Colors.Blue);
}
}
}
Hope this helps.
you need to add this to the top of your xaml with all of your xmlns's
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Related
I am trying to use generic windows in WPF. I know how to create them, but I have hard time specify resources or anything else in the root element in such a window. Is this possible? You can use x:TypeArguments only in the root tag, so I am afraid that any definition outside of the root tag won't get recognized and handled without generic specification. I am missing something here?
This is a minimal (non)functional code:
MainWIndow.xaml
<local:ViewBase x:Class="WpfApp1.MainWindow"
x:TypeArguments="local:TestViewModel"
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"
Title="MainWindow" Height="450" Width="800">
<local:ViewBase.Resources>
<ResourceDictionary>
<Style x:Key="TEST" TargetType="TextBlock">
<Setter Property="Foreground" Value="Red"/>
</Style>
</ResourceDictionary>
</local:ViewBase.Resources>
<Grid>
<TextBlock Text="TEST" Style="{StaticResource TEST}" />
</Grid>
MainWindow.xaml.cs
public partial class MainWindow : ViewBase<TestViewModel>
{
public MainWindow()
: base(null)
{
InitializeComponent();
}
public MainWindow(TestViewModel vm)
: base(vm)
{
InitializeComponent();
}
}
SomeClass.cs
public class ViewBase<T> : Window where T : ViewModelBase
{
public ViewBase(T vm)
{
DataContext = vm;
}
}
public class ViewModelBase
{
public ViewModelBase()
{
}
}
public class TestViewModel : ViewModelBase
{
public TestViewModel()
{
}
}
Just write Window.Resources:
<local:ViewBase ...>
<Window.Resources>
<ResourceDictionary>
<Style x:Key="TEST" TargetType="TextBlock">
<Setter Property="Foreground" Value="Red"/>
</Style>
</ResourceDictionary>
</Window.Resources>
<Grid>
<TextBlock Text="TEST" Style="{StaticResource TEST}" />
</Grid>
</local:ViewBase>
Following is the code of UI and code behind. There is no additional code than this.
Issues are
ListBox is not visible when I bind value to ObservableCollection with some delay.
ListBox is not in center of the popup. Can see in Design Viewer.
I tried placing ListBox out of popup and it works well. My need is to place listbox with in popup.
MainWindow.xaml
<Window x:Class="WPFTest.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:WPFTest"
mc:Ignorable="d"
Title="TestWPF" MinHeight="500" MinWidth="600"
WindowStyle="SingleBorderWindow" WindowStartupLocation="CenterScreen">
<Grid x:Name="mainContainer">
<Popup x:Name="popup" IsOpen="False" Margin="10" PlacementTarget="{Binding ElementName=mainContainer}"
Placement="Center" Height="300" Width="300">
<ListBox ItemsSource="{Binding InstallationSummary}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsEnabled" Value="False"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderThickness="0,0,0,1"
Margin="5" Padding="2">
<TextBlock Text="{Binding}"
TextWrapping="Wrap" Foreground="Black"/>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Popup>
</Grid>
</Window>
MainWindow.xaml.cs
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Windows;
namespace WPFTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
ObservableCollection<string> InstallationSummary;
public MainWindow()
{
InitializeComponent();
this.Loaded += MainWindow_Loaded;
InstallationSummary = new ObservableCollection<string>();
this.DataContext = this;
}
async private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
popup.IsOpen = true;
for (int i = 0; i < 25; i++)
{
await Task.Delay(1000);
App.Current.Dispatcher.Invoke(() =>
{
InstallationSummary.Add("New Item-" + i);
});
}
}
}
}
try converting your private variable
ObservableCollection InstallationSummary
to an public property like this
public ObservableCollection<string> InstallationSummary{ get set};
and should work fine..
i am trying to load user control in tab item dynamically but i am unable to do so i am using below code .I have visited various posts also but i have got the below way please let me know where i am wrong:
User control:
<UserControl x:Class="WpfApplication1.UserControl2"
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:WpfApplication1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Button Content="welcome" Height="20" Width="70"></Button>
</Grid>
</UserControl>
ViewMOdel:
namespace WpfApplication1
{
class Usercontrol2ViewModel
{
public ObservableCollection<TabItem> Tabs { get; set; }
public Usercontrol2ViewModel()
{
Tabs = new ObservableCollection<TabItem>();
//Tabs.Add(new TabItem { Header = "Overview", Content = new OverviewViewModel() }); How to load a usercontrol here if it's in the ItemCollection?
Tabs.Add(new TabItem { Header = "Overview", Content = new UserControl2() });
}
}
public class TabItem
{
public string Header { get; set; }
public object Content { get; set; } // object to allow all sort of items??
}
}
MainPage:
<TabControl x:Name="MyTabControl"
ItemsSource="{Binding Tabs}">
<TabControl.Resources>
<DataTemplate DataType="{x:Type local:Usercontrol2ViewModel}">
<local:UserControl2></local:UserControl2>
</DataTemplate>
</TabControl.Resources>
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding Header}" />
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
I found the issue below is the solution of code patch that needs to be correct above posted code
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding Header}" />
<Setter Property="Content" Value="{Binding Content}"></Setter>
</Style>
I have a custom control named Tile where containing a border.
I want to be able to change the Tile's border backcolor in my MainPage.xaml where I'm adding the control:
Here is the code of my tile class:
public static readonly DependencyProperty MyDpProperty = DependencyProperty.Register
("TileColor",
typeof(SolidColorBrush),
typeof(Tile),
new PropertyMetadata(default(SolidColorBrush)));
public SolidColorBrush TileColor
{
get
{
return (SolidColorBrush)this.GetValue(MyDpProperty);
}
set
{
this.SetValue(MyDpProperty, value);
}
}
Here is the xaml from my Tile CustomControl:
<Grid x:Name="LayoutRoot" Background="{StaticResource PhoneChromeBrush}">
<Border Background="{Binding TileColor}"></Border>
</Grid>
And here is my MainPage.xaml:
<local:Tile Grid.Column="5">
<local:Tile.TileColor>
<SolidColorBrush Color="Beige"></SolidColorBrush>
</local:Tile.TileColor>
</local:Tile>
The tile appears, but the color won't set..
Could you please point me where I'm wrong ?
You need to rename the DependencyProperty to TileColorProperty (as #dkozl says) and you also need to use {TemplateBinding} in the control:
Themes\generic.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:local="clr-namespace:Silverlight80App">
<Style TargetType="local:Tile">
<Setter Property="TileColor" Value="Aquamarine"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:Tile">
<Rectangle Fill="{TemplateBinding TileColor}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Tile.cs
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Silverlight80App
{
class Tile : ContentControl
{
public static readonly DependencyProperty TileColorProperty =
DependencyProperty.Register("TileColor", typeof(Brush), typeof(Tile),
null);
public Brush TileColor
{
get { return (Brush)GetValue(TileColorProperty); }
set { SetValue(TileColorProperty, value); }
}
public Tile()
{
DefaultStyleKey = typeof(Tile);
}
}
}
Usage
<StackPanel xmlns:local="clr-namespace:Silverlight80App">
<local:Tile HorizontalAlignment="Stretch" Height="10" />
<local:Tile HorizontalAlignment="Stretch" Height="10" TileColor="Red"/>
</StackPanel>
This works:
XAML:
<Window x:Class="Test239992.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<StackPanel>
<TextBlock Tag="1" Text="Customers" MouseDown="Handle_Click"/>
<TextBlock Tag="2" Text="Appointments" MouseDown="Handle_Click"/>
</StackPanel>
</Window>
Code Behind:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace Test239992
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void Handle_Click(object sender, MouseButtonEventArgs e)
{
int id = Int32.Parse(((TextBlock)sender).Tag.ToString());
MessageBox.Show("you chose id " + id.ToString());
}
}
}
But how do I put the MouseDown event in a style, this gives me the error "Cannot find the Style Property 'MouseDown' on the type 'System.Windows.Controls.TextBlock'":
<Window x:Class="Test239992.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<Style TargetType="{x:Type TextBlock}" x:Key="ClickableTextBlockStyle">
<Setter Property="MouseDown" Value="Handle_Click" />
</Style>
</Window.Resources>
<StackPanel>
<TextBlock Tag="1" Text="Customers" Style="{DynamicResource ClickableTextBlockStyle}"/>
<TextBlock Tag="2" Text="Appointments" Style="{DynamicResource ClickableTextBlockStyle}"/>
</StackPanel>
</Window>
Try EventSetter :)
<Style TargetType="{x:Type TextBlock}" x:Key="ClickableTextBlockStyle">
<EventSetter Event="MouseDown" Handler="Handle_Click" />
</Style>
Have a look at Triggers in WPF:
http://mark-dot-net.blogspot.com/2007/07/creating-custom-wpf-button-template-in.html