I have an UserControl that have Object Propdp:
public partial class HeaderControl : UserControl
{
public HeaderControl()
{
InitializeComponent();
DataContext = this;
}
public static readonly DependencyProperty ControlContentProperty =
DependencyProperty.Register(nameof(ControlContent), typeof(object),
typeof(HeaderControl), new PropertyMetadata(null));
public object ControlContent
{
get { return (object)GetValue(ControlContentProperty); }
set { SetValue(ControlContentProperty, value); }
}
}
In Xaml file:
<Grid Grid.Row="1">
<ContentControl Content="{Binding ControlContent, ElementName=root}"/>
</Grid>
if i use it without give a Name to the Button inside it works:
<ctrl:HeaderContorl >
<ctrl:HeaderContorl.ControlContent>
<Button Content="Hallooo" FontSize="40"
Foreground="Black" Height="100"/>
</ctrl:HeaderContorl.ControlContent>
</ctrl:HeaderContorl>
But if i name the Button inside it not works:
<ctrl:HeaderContorl >
<ctrl:HeaderContorl.ControlContent>
<Button x:Name="Btn" Content="Hallooo" FontSize="40"
Foreground="Black" Height="100"/>
</ctrl:HeaderContorl.ControlContent>
</ctrl:HeaderContorl>
Can someone please tell me why I can't name the button inside?
Related
In my application I have a usercontrol called "ChannelControls" placed six times in six differents TabItems. The whole things is contains in an other tabcontrol. So basically, two levels of TabControls.
But since I've done that, all property stay empty and doesn't output anything. So I guess that's a datacontext problem.
Datacontext for the UserControl :
public partial class ChannelControls : UserControl
{
public ChannelControls()
{
InitializeComponent();
this.DataContext = this;
}
one of its property :
public static readonly DependencyProperty VidTranslateNamesProperty =
DependencyProperty.Register("VidTranslateNames", typeof(ObservableCollection<string>), typeof(ChannelControls));
[Bindable(true)]
public ObservableCollection<string> VidTranslateNames
{
get { return (ObservableCollection<string>)this.GetValue(VidTranslateNamesProperty); }
set { this.SetValue(VidTranslateNamesProperty, value); }
}
This is how the usercontrol is placed in one of the tabitems :
<Grid Grid.Row="1">
<TabControl x:Name="MainBoard" Style="{DynamicResource BaseTabControlStyle}" TabStripPlacement="Top" HorizontalContentAlignment="Center">
<TabItem x:Name="Channels" Header="CHANNELS" Style="{DynamicResource BaseTabItemStyle}" Background="{x:Null}" FontFamily="Bebas Neue Book" Margin="0" Height="30" Width="100" VerticalAlignment="Top" d:LayoutOverrides="Height">
<Grid x:Name="ChannelsContent" Margin="4, 4, 4, 4" DockPanel.Dock="Left">
<TabControl x:Name="ContentSelector" Style="{DynamicResource BaseTabControlStyle}" TabStripPlacement="Right" HorizontalContentAlignment="Center">
<TabItem x:Name="Channel0" IsSelected="True" Header="1" Style="{DynamicResource BaseTabItemStyle}" Height="45" Width="25" Background="{x:Null}" FontFamily="Bebas Neue Book">
<CMiX:ChannelControls Tag="0" VidTranslateNames="{Binding VideoTranslateNames, ElementName=cmix, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</TabItem>
</TabControl>
</Grid>
</TabItem>
</TabControl>
</Grid>
hmm why you have there :
ElementName=cmix
I working with static property mainly like this:
private static DependencyProperty _VidTranslateNamesProperty;
public static event EventHandler VidTranslateNamesPropertyChanged;
public static double VidTranslateNamesProperty
{
get { return _VidTranslateNamesProperty; }
set
{
_VidTranslateNamesProperty = value;
RaiseVidTranslateNamesPropertyChanged();
}
}
public static void RaiseVidTranslateNamesPropertyChanged()
{
EventHandler handler = VidTranslateNamesPropertyChanged;
if (handler != null)
handler(null, new EventArgs.Empty);
}
then you can bind it like
DependencyProperty ="{Binding Path=(local:Class.VidTranslateNamesProperty)}"
OK found the problem. Because I changed the name of the parent usercontrol, I forget to change ElementName everywhere I bind properties. As VisualStudio didn't raised any error, I needed time to find it...
Thank you anyway for the help.
I have tried to google this but I am not super clear on the suggestions I see people making.
I have 3 buttons within a user control that are exactly the same except for automation id and text. Instead of duplicating this code across all buttons, I would like to create a common control or control template that I can use. My problem is these buttons have nested controls whose text I need to change but I'm not sure how to do this.
<UserControl>
<Grid>
<StackPanel x:Name="myStackPanel" Grid.Row="1" Padding="0">
<Button AutomationProperties.AutomationId="CallButton" x:Name="CallButton" Style="{StaticResource ButtonStyle}">
<RelativePanel>
<SymbolIcon AutomationProperties.AutomationId="CallIcon" x:Name="CallIcon" Symbol="Phone" Style="{StaticResource SymbolStyle}" />
<StackPanel>
<TextBlock AutomationProperties.AutomationId="CallLabel" Text="Call" Style="{StaticResource LabelStyle}"/>
<TextBlock AutomationProperties.AutomationId="CallText" Text="123-456-7890" Style="{StaticResource ContentStyle}"/>
</StackPanel>
</RelativePanel>
</Button>
<Button AutomationProperties.AutomationId="EmailButton" x:Name="EmailButton" Style="{StaticResource ButtonStyle}">
<RelativePanel>
<SymbolIcon AutomationProperties.AutomationId="EmailIcon" x:Name="EmailIcon" Symbol="Mail" Style="{StaticResource SymbolStyle}"/>
<StackPanel >
<TextBlock AutomationProperties.AutomationId="EmailLabel" Text="Email" Style="{StaticResource LabelStyle}"/>
<TextBlock AutomationProperties.AutomationId="EmailText" Text="meetme#email.com" Style="{StaticResource ContentStyle}"/>
</StackPanel>
</RelativePanel>
</Button>
<Button AutomationProperties.AutomationId="WebsiteButton" x:Name="WebsiteButton" Style="{StaticResource ButtonStyle}">
<RelativePanel>
<SymbolIcon AutomationProperties.AutomationId="WebsiteIcon" x:Name="WebsiteIcon" Symbol="Link" Style="{StaticResource SymbolStyle}"/>
<StackPanel >
<TextBlock AutomationProperties.AutomationId="WebsiteLabel" Text="Website" Style="{StaticResource LabelStyle}"/>
<TextBlock AutomationProperties.AutomationId="WebsiteText" Text="http://meetme.com" Style="{StaticResource ContentStyle}"/>
</StackPanel>
</RelativePanel>
</Button>
</StackPanel>
</Grid>
</Grid>
As you can see, the code for all 3 buttons is same. All I want to do is create a control where I can set the automation ids and text properties of the nested controls.
Thanks!
You can create a button based on a UserControl (add a new UserControl). It will allow you to enjoy all the default button's properties, events and states (OnClick, Command, etc.) and to add your own properties, template and behavior.
Using dependency properties instead of simple properties is strongly advised if you want to use bindings or animations on them.
C#:
public partial class CustomButton : Button
{
#region IconAutomationId
public string IconAutomationId
{
get { return (string)GetValue(IconAutomationIdProperty); }
set { SetValue(IconAutomationIdProperty, value); }
}
public static readonly DependencyProperty IconAutomationIdProperty =
DependencyProperty.Register("IconAutomationId", typeof(string), typeof(CustomButton), new PropertyMetadata(null));
#endregion
#region LabelAutomationId
public string LabelAutomationId
{
get { return (string)GetValue(LabelAutomationIdProperty); }
set { SetValue(LabelAutomationIdProperty, value); }
}
public static readonly DependencyProperty LabelAutomationIdProperty =
DependencyProperty.Register("LabelAutomationId", typeof(string), typeof(CustomButton), new PropertyMetadata(null));
#endregion
#region TextAutomationId
public string TextAutomationId
{
get { return (string)GetValue(TextAutomationIdProperty); }
set { SetValue(TextAutomationIdProperty, value); }
}
public static readonly DependencyProperty TextAutomationIdProperty =
DependencyProperty.Register("TextAutomationId", typeof(string), typeof(CustomButton), new PropertyMetadata(null));
#endregion
#region Symbol
public object Symbol
{
get { return (object)GetValue(SymbolProperty); }
set { SetValue(SymbolProperty, value); }
}
public static readonly DependencyProperty SymbolProperty =
DependencyProperty.Register("Symbol", typeof(object), typeof(CustomButton), new PropertyMetadata(null));
#endregion
#region Label
public string Label
{
get { return (string)GetValue(LabelProperty); }
set { SetValue(LabelProperty, value); }
}
public static readonly DependencyProperty LabelProperty =
DependencyProperty.Register("Label", typeof(string), typeof(CustomButton), new PropertyMetadata(null));
#endregion
#region Text
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(CustomButton), new PropertyMetadata(null));
#endregion
public CustomButton()
{
InitializeComponent();
}
}
XAML:
<Button x:Class="WpfApplication1.CustomButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="customButton">
<RelativePanel>
<SymbolIcon AutomationProperties.AutomationId="{Binding IconAutomationId, ElementName=customButton}"
Symbol="{Binding Symbol, ElementName=customButton}"
Style="{StaticResource SymbolStyle}"/>
<StackPanel >
<TextBlock AutomationProperties.AutomationId="{Binding LabelAutomationId, ElementName=customButton}"
Text="{Binding Label, ElementName=customButton}"
Style="{StaticResource LabelStyle}"/>
<TextBlock AutomationProperties.AutomationId="{Binding TextAutomationId, ElementName=customButton}"
Text="{Binding Text, ElementName=customButton}"
Style="{StaticResource ContentStyle}"/>
</StackPanel>
</RelativePanel>
</Button>
Use:
<local:CustomButton AutomationProperties.AutomationId="CallButton"
x:Name="CallButton"
Style="{StaticResource ButtonStyle}"
IconAutomationId="CallIcon"
LabelAutomationId="CallLabel"
TextAutomationId="CallText"
Symbol="Phone"
Label="Call"
Text="123-456-7890"/>
It may be more work than you feel like doing but it sounds like you're going to want to create a UserControl. It should inherit from Button in the code-behind:
public partial class MyButton: Button
In the XAML you will include essentially the guts of what you have in each of the buttons now.
The tedious part is that you will then (in the code-behind) need to create a DependencyProperty for each of the "properties" you will want to set in this control: for example, one for the CallIconAutomationId, one for the CallLabelAutomationId, one for the CallLabelText, etc. You will then bind each of these properties in the XAML to the dependency property. These properties become the data that you will set on each individual MyButton (your new UserControl).
Then, in the container that is hosting these controls (which appears to be another UserControl in your example above) you would set these custom properties on each of your new MyButton controls, which will look something like this:
<myNamespace:MyButton EmailIconAutomationId="EmailIcon" LabelAutomationId="EmailLabel" />
etc.
Basically, you're creating a new control (a UserControl) based on the Button control (which gives you most of your functionality) and adding new custom properties directly to that new control (which work just like all the other control properties you're accustomed to).
I have a UserControl that works perfectly at run time except the default values. I have used the same UserControl (MaterialUserControl) in two different Tabs in the MainWindow. In one of the Tabs it's default values (RadioButton isChecked values) work fine but not the other?
//This is the one which is not setting its default values!
<l:MaterialUserControl x:Name="materialShellUC" stainlessSteelBool="True" Click="shellMaterialBtn_Click" plateBool="True" ENBool="True"/>
//This one is in another Tab
<l:MaterialUserControl x:Name="materialDishUC" Width="500" HorizontalAlignment="Left" Click="materialDish_Click" plateBool="True" stainlessSteelBool="True" ENBool="True"/>
public partial class MaterialUserControl : UserControl
{
public MaterialUserControl()
{
InitializeComponent();
rootGrid.DataContext = this;
}
public static readonly DependencyProperty MaterialProperty =
DependencyProperty.Register("Material", typeof(string),
typeof(MaterialUserControl), new PropertyMetadata(""));
public String Material
{
get { return (String)GetValue(MaterialProperty); }
set { SetValue(MaterialProperty, value); }
}
public static readonly DependencyProperty MaterialNoProperty =
DependencyProperty.Register("MaterialNo", typeof(string),
typeof(MaterialUserControl), new PropertyMetadata(""));
public String MaterialNo
{
get { return (String)GetValue(MaterialNoProperty); }
set { SetValue(MaterialNoProperty, value); }
}
public event RoutedEventHandler Click;
void onButtonClick(object sender, RoutedEventArgs e)
{
if (this.Click != null)
this.Click(this, e);
}
public static readonly DependencyProperty stainlessSteelBoolProperty =
DependencyProperty.Register("strainlessSteelBool", typeof(bool), typeof(MaterialUserControl), new PropertyMetadata(null));
public bool stainlessSteelBool
{
get { return (bool)GetValue(stainlessSteelBoolProperty); }
set { SetValue(stainlessSteelBoolProperty, value); }
}
public static readonly DependencyProperty plateBoolProperty =
DependencyProperty.Register("plateBool", typeof(bool), typeof(MaterialUserControl), new PropertyMetadata(null));
public bool plateBool
{
get { return (bool)GetValue(plateBoolProperty); }
set { SetValue(plateBoolProperty, value); }
}
public static readonly DependencyProperty ENBoolProperty =
DependencyProperty.Register("ENBool", typeof(bool), typeof(MaterialUserControl), new PropertyMetadata(null));
public bool ENBool
{
get { return (bool)GetValue(ENBoolProperty); }
set { SetValue(ENBoolProperty, value); }
}
}
//here is the UserControl XAML
<Grid Background="Pink" x:Name="rootGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Text="Material" Grid.Row="0" Foreground="DarkBlue"/>
<RadioButton Content="ASME" Grid.Row="1" GroupName="a"/>
<RadioButton Content="EN" Grid.Row="1" Grid.Column="1" GroupName="a" IsChecked="{Binding ENBool}"/>
<RadioButton Content="Plate" IsChecked="{Binding plateBool}" Grid.Row="2" GroupName="b"/>
<RadioButton Content="Tube" Grid.Row="2" Grid.Column="1" GroupName="b"/>
<RadioButton Content="Stainless steel" Grid.Row="3" GroupName="c" IsChecked="{Binding stainlessSteelBool}"/>
<RadioButton Content="Carbon Steel" Grid.Row="3" Grid.Column="1" GroupName="c"/>
<Button Content="Material" Grid.Row="4" Click="onButtonClick"/>
<TextBox Grid.Row="4" Grid.Column="1" IsReadOnly="True" Text="{Binding Path=Material}"/>
<TextBox Grid.Row="4" Grid.Column="2" IsReadOnly="True" Text="{Binding Path=MaterialNo}"/>
</Grid>
Is it something to do with the DataContext?
Changes appear in the VS designer but all the RadioButtons value stays null.
Because you are setting the default values to the dependency properties to be null. Instead of null, set them to false (or true depending on your requirements)
public static readonly DependencyProperty plateBoolProperty =
DependencyProperty.Register("plateBool", typeof(bool), typeof(MaterialUserControl), new PropertyMetadata(false));
I would guess this is because the radio buttons in one tab use the same GroupName as the radio buttons in another tab, so they are considered part of the same logical group even though they are spread across tabs: when you select a radio button in one tab, you deselect a radio button in the corresponding group of another tab. Try generating unique group names.
Also, null is not a valid default value for a property of type bool; either make the default value false, or migrate your properties to type bool?.
I want to create a custom control(or user control) which has both a textblock and a textbox as in the fig below:
Both the textblock and Textbox text properties are to be bound to the database fields and be able to apply styling etc. Which is the best approach for the same?
I have come up with a solution as below:
XAML for user control:
<UserControl x:Class="TestDependency.TextBlox"
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"
x:Name="abc"
DataContext="{Binding RelativeSource={RelativeSource Self}}" >
<Grid Width="170">
<TextBlock Height="23" HorizontalAlignment="Left" Margin="0,1,0,0"
Text="{Binding Path=Caption}"
VerticalAlignment="Top" Width="52" />
<TextBox Height="25" HorizontalAlignment="Left" Margin="53,-2,0,0"
x:Name="TextBox1"
Text="{Binding Path=Value}"
VerticalAlignment="Top" Width="120" />
</Grid>
Code behind for Usercontrol:
public partial class TextBlox : UserControl
{
public TextBlox()
{
InitializeComponent();
}
public static DependencyProperty CaptionProperty = DependencyProperty.Register("Caption", typeof(string), typeof(TextBlox));
public static DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(string), typeof(TextBlox));
public string Caption
{
get
{
return (string)GetValue(CaptionProperty);
}
set
{
SetValue(CaptionProperty, value);
}
}
public string Value
{
get
{
return (string)GetValue(ValueProperty);
}
set
{
SetValue(ValueProperty, value);
}
}
static void ValueChangedCallBack(DependencyObject property, DependencyPropertyChangedEventArgs args)
{
TextBlox inst = (TextBlox)property;
inst.TextBox1.Text = (string)args.NewValue;
}
}
XAML for actual form where Usercontrol is used:
<Grid x:Name="grdmain">
<my:TextBlox Caption="{Binding XValue, Mode=TwoWay}" Value="{Binding WindowName, Mode=TwoWay}"
HorizontalAlignment="Left" Margin="246,197,0,0" x:Name="textBlox1" VerticalAlignment="Top" />
</Grid>
Code behind:
public partial class MainWindow : Window
{
DataEntities dt = new DataEntities();
CoOrdinate oCord;
public MainWindow()
{
InitializeComponent();
Loaded += new RoutedEventHandler(MainWindow_Loaded);
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
oCord = dt.CoOrdinates.First();
grdmain.DataContext = oCord;
}
}
Still the binding doesnt work. But the code :
textBlox1.Caption = "test";
is working fine. where am I wrong?
Create an user control with a textblock and textbox and bind the values to that control.
<YourUserControl TextBlockText="{Binding TextBlockText}" TextBoxText="{Binding TextBoxText, Mode=TwoWay}"/>
I have a UserControl which acts as a wrapper for a ContentControl, which is simply a title to the ContentControl.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Background="Green" Grid.Row="0">
<TextBlock Text="{Binding Header}" Style="{StaticResource HeaderStyle}" Margin="12, 10, 0, 10" />
</Grid>
<ContentControl HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" Content="{Binding Body}" Grid.Row="1"/>
</Grid>
And here's where I try to use the control:
<gbl:ListHeader Grid.Row="1" Visibility="{Binding HasMovies, Converter={StaticResource VisibilityConverter}}" Header="{Binding Path=LocalizedResources.movie_list_header, Source={StaticResource LocalizedStrings}}" >
<gbl:ListHeader.Body>
<ListBox SelectionChanged="ListBoxContainerSelectionChanged" ItemsSource="{Binding Movies}" ItemContainerStyle="{StaticResource HeaderListBoxItemStyle}">
<ListBox.ItemTemplate>
<DataTemplate>
<gbl:MovieItemControl Header="{Binding MovieTitle}" Description="{Binding FormattedDescription}" Detail="{Binding FormattedDetail}" Opacity="{Binding IsSuppressed, Converter={StaticResource DimIfTrueConverter}}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</gbl:ListHeader.Body>
The DataBinding to the list happens, however nothing displays in the control. I'm guessing that it's still there, but too small to see (undefined h/w).
Is there something that I'm doing wrong? The header shows fine, so the control appears to be working somewhat.
Edit:
Here's the code-behind for ListHeader:
public partial class ListHeader : UserControl
{
private readonly ListHeaderData _data = new ListHeaderData();
public ListHeader()
{
InitializeComponent();
DataContext = _data;
}
public string Header
{
get { return (string)GetValue(HeaderProperty); }
set { SetValue(HeaderProperty, value); }
}
// Using a DependencyProperty as the backing store for Header. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.Register("Header", typeof(string), typeof(ListHeader), new PropertyMetadata("",HeaderPropertyChanged) );
private static void HeaderPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var lh = d as ListHeader;
if (lh != null)
lh._data.Header = e.NewValue as string;
}
public object Body
{
get { return GetValue(BodyProperty); }
set { SetValue(BodyProperty, value); }
}
// Using a DependencyProperty as the backing store for Body. This enables animation, styling, binding, etc...
public static readonly DependencyProperty BodyProperty =
DependencyProperty.Register("Body", typeof(object), typeof(ListHeader), new PropertyMetadata(null, BodyPropertyChanged));
private static void BodyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var lh = d as ListHeader;
if (lh != null)
lh._data.Body = e.NewValue;
}
}
public class ListHeaderData : ViewModelBase
{
public ListHeaderData()
{
if (IsInDesignMode)
{
Header = "Custom Header Goes Here";
Body = new Grid() { Background = new SolidColorBrush(Colors.Yellow) };
}
}
private string _header;
public string Header
{
get { return _header; }
set { _header = value; RaisePropertyChanged("Header"); }
}
private object _body;
public object Body
{
get { return _body; }
set { _body = value; RaisePropertyChanged("Body");}
}
}
In addition to what i said in my comment you appear to bind to your DataContext in the UserControl declaration which is a Bad Thing and the problem of all this.
You appear to want to bind to the properties of the UserControl but you bind directly to the properties of the DataContext which is your ViewModel, hence setting the Body property on an instance in XAML does nothing as the property is sidestepped by the internal binding.
UserControls should for all i know do bindings like this:
<UserControl Name="control" ...>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Background="Green" Grid.Row="0">
<TextBlock Text="{Binding Header, ElementName=control}" Style="{StaticResource HeaderStyle}" Margin="12, 10, 0, 10" />
</Grid>
<ContentControl HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" Content="{Binding Body, ElementName=control}" Grid.Row="1"/>
</Grid>
Get rid of those dependency property changed callbacks and change the property code in ViewModels to this format to make sure it changed:
private int _MyProperty = 0;
public int MyProperty
{
get { return _MyProperty; }
set
{
if (_MyProperty != value)
{
_MyProperty = value;
OnPropertyChanged("MyProperty");
}
}
}