How do I add additional properties to a text box - c#

I'm trying to add a couple of custom properties to textboxes in my application , it will help me reduce the lines of code needed drastically..
C# Code for adding the property
class HorizonTextBoxExt:TextBox
{
public HorizonTextBoxExt() : base() { }
public bool BoundToDataGrid
{
get { return (bool)this.GetValue(BoundToDataGridProperty); }
set { this.SetValue(BoundToDataGridProperty, value); }
}
public static readonly DependencyProperty BoundToDataGridProperty =
DependencyProperty.Register(
"BoundToDataGrid",
typeof(bool),
typeof(HorizonTextBoxExt),
new UIPropertyMetadata(false)
);
}
"Error 3 The attachable property 'BoundToDataGrid' was not found in
type HorizonTextBoxExt'.
is the error I get in the xaml wind of the wpf designer
<Window x:Class="WpfApplication7.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Local ="clr-namespace:WpfApplication7"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBox HorizontalAlignment="Left" Height="63" Margin="90,47,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="225" Local:HorizonTextBoxExt.BoundToDataGrid="true" />
</Grid>
</Window>

Replace this:
<Grid>
<TextBox /* ... */ Local:HorizonTextBoxExt.BoundToDataGrid="true" />
</Grid>
with this:
<Grid>
<Local:HorizonTextBoxExt /* ... */ BoundToDataGrid="true" />
</Grid>

Related

Simple popup dialog in WPF (overlay inside Window)

I'm working on a modal dialog popup (I'm not sure about the exact UX term) that is displayed inline, inside of a control or window with darkened background.
Visual example
What I tried is putting a <ContentPresenter /> inside the XAML of the popup and then just instantiate it like this:
<local:Popup Grid.RowSpan="2">
<TextBlock Text="Popup test..." />
</local:Popup>
However, the XAML replaces the entire Popup XAML instead of being placed where the ContentPresenter is.
Q: How is the ContentPresenter here used properly?
Popup.xaml
<ContentControl
x:Class="[...].Popup"
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:[...]"
mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="300">
<Grid Background="#7f000000">
<Grid Background="White" HorizontalAlignment="Center" VerticalAlignment="Center">
<StackPanel Margin="20">
<TextBlock Text="{Binding Title, RelativeSource={RelativeSource AncestorType=UserControl}}" FontSize="20" />
<ContentPresenter />
</StackPanel>
</Grid>
</Grid>
</ContentControl>
Popup.xaml.cs
using System.Windows;
namespace [...]
{
public partial class Popup : ContentControlBase
{
public static DependencyProperty TitleProperty = DependencyProperty.Register(nameof(Title), typeof(string), typeof(Popup));
public string Title
{
get
{
return (string)GetValue(TitleProperty);
}
set
{
SetValue(TitleProperty, value);
}
}
public Popup()
{
InitializeComponent();
}
}
}
The content of your Popup should be defined as a ControlTemplate for the ContentPresenter to work as expected here. Please refer to the following sample code.
Popup.xaml:
<ContentControl
x:Class="WpfApplication1.Popup"
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:DesignWidth="300" d:DesignHeight="300"
x:Name="popup">
<ContentControl.Template>
<ControlTemplate TargetType="local:Popup">
<Grid Background="#7f000000">
<Grid Background="White" HorizontalAlignment="Center" VerticalAlignment="Center">
<StackPanel Margin="20">
<TextBlock Text="{Binding Title, ElementName=popup}" FontSize="20" />
<ContentPresenter />
</StackPanel>
</Grid>
</Grid>
</ControlTemplate>
</ContentControl.Template>
Popup1.xaml.cs.
public partial class Popup : ContentControl
{
public static DependencyProperty TitleProperty = DependencyProperty.Register(nameof(Title), typeof(string), typeof(Popup));
public string Title
{
get
{
return (string)GetValue(TitleProperty);
}
set
{
SetValue(TitleProperty, value);
}
}
public Popup()
{
InitializeComponent();
}
}
}
Window1.xaml:
<local:Popup Title="Title...">
<TextBlock>Text...</TextBlock>
</local:Popup>

Custom property and communicating data between view-models

I'm trying to build a simple app that has a control that defines player's name and their style. This control is reused for player 1 and player 2. The first goal is to set two radio button groups so that each player gets to select accordingly. The second is to communicate the data from this control to the main page's view model. How do I accomplish these things?
Here's what the control looks like:
The following is the project structure:
Player.cs simply holds reference to the player's style and their name
namespace temp
{
class Player
{
// offensive / defensive
public string Style { get; set; }
public string Name { get; set; }
}
}
It also acts as the view model for PlayerInfoControl. Here's the code for it:
<UserControl x:Class="temp.Controls.PersonInfoControl"
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:temp.Controls"
xmlns:vm="clr-namespace:temp"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<vm:Player x:Key="ViewModel" />
</UserControl.Resources>
<Grid DataContext="{StaticResource ViewModel}">
<StackPanel Orientation="Horizontal" Height="50">
<StackPanel Margin="0,0,15,0" VerticalAlignment="Center">
<RadioButton Content="Offense" GroupName="{Binding Group}" />
<RadioButton Content="Defense" GroupName="{Binding Group}" />
</StackPanel>
<StackPanel Margin="0,0,15,0" Orientation="Horizontal" VerticalAlignment="Center">
<Label Content="Name" />
<TextBox Width="100" Height="25" Text="{Binding Name}"/>
</StackPanel>
</StackPanel>
</Grid>
</UserControl>
MainWindow is a simple grid that defines the playerInfoControl twice
<Window x:Class="temp.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:temp"
xmlns:controls="clr-namespace:temp.Controls"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:MainWindowViewModel x:Key="ViewModel" />
</Window.Resources>
<Grid DataContext="{StaticResource ViewModel}">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="160" />
</Grid.RowDefinitions>
<controls:PersonInfoControl Grid.Row="0" Group="p1" />
<controls:PersonInfoControl Grid.Row="1" Group="p2" />
</Grid>
</Window>
Lastly, there's MainWindowViewModel that I need to relay the data to, that's captured by PlayInfoControl.
namespace temp
{
class MainWindowViewModel
{
Player Player1 = new Player();
Player Player2 = new Player();
}
}
I'm first trying to solve setting the group. I created a custom dependency property, however by app fails to build because of it and I'm not sure what I'm doing wrong.
public partial class PersonInfoControl : UserControl
{
public PersonInfoControl()
{
InitializeComponent();
}
public string Group
{
get { return (string)GetValue(GroupProperty); }
set { SetValue(GroupProperty, value); }
}
// Using a DependencyProperty as the backing store for Group. This enables animation, styling, binding, etc...
public static readonly DependencyProperty GroupProperty =
DependencyProperty.Register("Group", typeof(string), typeof(Player), new PropertyMetadata(0));
}
This is what the error looks like:
You need to use the correct type for the default value of your dependency property. In your case its 0 which cannot be assigned to a string. Replace
new PropertyMetadata(0));
with
new PropertyMetadata(string.Empty));

WPF data binding through UserControls

I would like to bind property from the main window's DataContext, above you can see my UserControls and models. So I want to bind the Model.ID.Label1 and Model.ID.Label2 properties to the main_id/card_1/top and main_id/card_1/bottom controls. I hope it's clear. If I enable the
ref_lbl Label it will shows the "lbl1", the card_2 still working with the hardcoded texts but the card_1 will be blank. What should I modify to fix the binding on card_1?
I have an ID UserControl and it contains another UserControl.
XAML:
<UserControl x:Class="stack.ID"
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:Controls="clr-namespace:stack.Controls"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Label Name="ref_lbl" Grid.Row="0" Content="{Binding Label1}" Visibility="Collapsed" />
<Controls:Card x:Name="card_1" Grid.Row="0" TopLabel="{Binding Label1}" BottomLabel="{Binding Label2}" />
<Controls:Card x:Name="card_2" Grid.Row="1" TopLabel="Text 1" BottomLabel="Text 2" />
</Grid>
Code Behind: default, auto generated
Here is the Card UserControl.
XAML:
<UserControl x:Class="stack.Controls.Card"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Label Grid.Row="0" FontSize="20" Foreground="Black" HorizontalAlignment="Center" VerticalAlignment="Center" Content="{Binding TopLabel}" />
<Label Grid.Row="1" FontSize="20" Foreground="Black" HorizontalAlignment="Center" VerticalAlignment="Center" Content="{Binding BottomLabel}" />
</Grid>
Code Behind:
namespace stack.Controls
{
public partial class Card : UserControl
{
public static readonly DependencyProperty TopLabelProperty = DependencyProperty.Register("TopLabel", typeof(string), typeof(Card), new PropertyMetadata(default(string)));
public static readonly DependencyProperty BottomLabelProperty = DependencyProperty.Register("BottomLabel", typeof(string), typeof(Card), new PropertyMetadata(default(string)));
public Card()
{
InitializeComponent();
}
public string TopLabel
{
get
{
return (string)GetValue(TopLabelProperty);
}
set
{
SetValue(TopLabelProperty, value);
}
}
public string BottomLabel
{
get
{
return (string)GetValue(BottomLabelProperty);
}
set
{
SetValue(BottomLabelProperty, value);
}
}
}
}
And here is my main window.
XAML:
<Window x:Class="stack.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:stack"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:Model />
</Window.DataContext>
<Grid>
<local:ID x:Name="main_id" DataContext="{Binding ID}" />
</Grid>
Code Behind: default, auto generated
And I also have 2 models.
namespace stack
{
public class IDModel
{
private string label1 = "lbl1";
private string label2 = "lbl2";
public string Label1
{
get
{
return label1;
}
set
{
label1 = value;
}
}
public string Label2
{
get
{
return label2;
}
set
{
label2 = value;
}
}
}
public class Model
{
private IDModel id = new IDModel();
public IDModel ID
{
get
{
return id;
}
set
{
id = value;
}
}
}
}
Remove
DataContext="{Binding RelativeSource={RelativeSource Self}}"
from the Card's XAML.
It prevents inheriting the DataContext from its parent ID control, which is necessary when you write
<Controls:Card ... TopLabel="{Binding Label1}" />
Instead write the Content bindings in Card's XAML like this:
<Label ... Content="{Binding TopLabel,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}" />

Get property value WPF

I am trying get a value from a property but isn't working I always get a null value.
string imageNormal;
public static readonly DependencyProperty ImageNormalProperty =
DependencyProperty.Register("ImageNormal", typeof(string), typeof(MainWindow));
public string ImageNormal
{
get { return (string)GetValue(ImageNormalProperty); }
set { SetValue(ImageNormalProperty, value); }
}
public ButtonImageStyle()
{
InitializeComponent();
DataContext = this;
Console.WriteLine("Path: " + ImageNormal);
}
Xaml ButtonImageStyle.xaml:
<Image Source="{Binding ImageNormal}" Stretch="None" HorizontalAlignment="Center" VerticalAlignment="Center" />
Xaml MainWindow.xaml:
<local:ButtonImageStyle HorizontalAlignment="Left" Height="60" VerticalAlignment="Top" Width="88" ImageNormal="C:/Users/Xafi/Desktop/add.png"/>
I always obtain next output:
Path:
since your ImageSource is have to be binded to it's parent DependencyProperty (which is defined to your code behind), you have to define your binding to be rlative to your UserControl (let's name it This). Thus please try to change your xaml in the next way:
Xaml code
<UserControl x:Class="SomeBindingExampleSOHelpAttempt.ButtonImageStyle"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" x:Name="This">
<Grid>
<Image Source="{Binding ElementName=This, Path=ImageNormal, UpdateSourceTrigger=PropertyChanged}"
Stretch="None" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid></UserControl>
Here you can find an additional perfect answer.
Regards.

WPF controls not showing up in ItemTemplate(Listbox/ListView)

I have recently started with XAML and WPF. I just created a new project in wpf and add the below XAML code. But...none of the items which are added inside "Listbox.ItemTemplate" or "ListView.ItemTemplate" for that matter show up in designer window. what am i doing wrong? This is a fresh project and so no code-behind stuff added yet. i scratched my head for 15 mins with this but with no success. Please help
<Window x:Class="WpfApplication3.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 Margin="10">
<ListBox Margin="10">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Name: " />
<TextBlock Text="Age: " />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
You should bind your ListBox or entire Window to some DataContext (usually this is viewmodel with the data you need to display) or specify items of the list explicitly.
In your snippet you specified only an item template, not the items itself.
The example of XAML-defined items (simple strings):
<Window x:Class="WpfApplication3.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 Margin="10">
<ListBox Margin="10">
<ListBox.Items>
<ListBoxItem>123</ListBoxItem>
<ListBoxItem>456</ListBoxItem>
</ListBox.Items>
</ListBox>
</Grid>
</Window>
The example with DataContext and Bindings.
XAML:
<Window x:Class="WpfApplication3.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 Margin="10">
<ListBox Margin="10" ItemsSource="{Binding Path=Persons}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label>Name:</Label><TextBlock VerticalAlignment="Center" Text="{Binding Path=Name}" />
<Label>Age:</Label><TextBlock VerticalAlignment="Center" Text="{Binding Path=Age}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
Codebehind:
namespace WpfApplication3
{
public class PersonViewModel
{
public PersonViewModel(string name, int age)
{
this.name = name;
this.age = age;
}
public string Name
{
get { return name; }
}
private string name;
public int Age
{
get { return age; }
}
private int age;
}
public class MainViewModel
{
public MainViewModel()
{
persons = new ObservableCollection<PersonViewModel>()
{
new PersonViewModel("Lez", 146),
new PersonViewModel("Binja", 158),
new PersonViewModel("Rufus the Destroyer", 9000)
};
}
public ObservableCollection<PersonViewModel> Persons
{
get { return persons; }
}
private ObservableCollection<PersonViewModel> persons;
}
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainViewModel();
}
}
}
IMPORTANT: Don't forget to properly implement INotifyPropertyChanged in case of mutable properties of viewmodels (for example, if you will have setters for "Name" and "Age" properties of PersonViewModel).
You don't see any items because your ListBox doesn't contain any data in the designer view. To populate it, a list should be binded to the property "ItemsSource" of your ListBox, or adding datas directly to the property "Items" (XAML or code behind).
If you want to show items in the designer view properly, you should have a ViewModel binding to the DataContext of your page and create a "Sample data" file (via Blend for example).
Item Templates are basically used to show customize data. Just Use simple string items first. It will show in list box.

Categories