I want to Change the Style of a Grid dynamically. For that Purpose let's suppose I have 3 Textblocks with 3 Contents defined.
<TextBlock x:Name="Block1" Text="key1" />
<TextBlock x:Name="Block2" Text="key2" />
<TextBlock x:Name="Block3" Text="key3" />
For each of the keys (1,2,3) there is a Style defined with the Name x:Key="key1".
Now i want something like this in my Grid:
<Grid Style="{DynamicResource {Binding ElementName=Block1, Path=Text}} />
Is this possible in Default XAML or do I have to find a Workaround?
Is this possible in Default XAML or do I have to find a Workaround?
No, I am afraid you cannot use the StaticResource or DynamicResource markup extension with "dynamic" values like this. The keys of the resources must be known at compile time.
Binding to a property and use a converter would be one way:
<Grid Style="{Binding ElementName=Block1, Path=Text, Converter={StaticResource converter}}">
But I guess that's a workaround.
Related
I'm trying to use the PropertyGrid component from PropertyTools to display information on an object. I can bind the object easily enough -- it's a property on my DataContext -- but one of the things that can't be derived from the object is the name that should be displayed in the tab header. (And I can't change that; the object I'm inspecting comes from a third party.) The proper name is a different property on my DataContext.
PropertyGrid has a way to change the way the tab header is displayed, by passing a DataTemplate to its TabHeaderTemplate property. But something bizarre happens inside of the template: my DataContext is gone, replaced by something else. When I try to say {Binding TabName} in the appropriate place inside the context, it errors out and tells me that TabName is not a valid property on class Tab. But my DataContext class isn't called Tab; that's something inside of PropertyTools's codebase!
I'm still new to WPF, so I have no clue what's going on here. Why is the in-scope DataContext that's perfectly valid in the rest of the XAML file being yoinked out from under me inside this template, and how can I fix it?
EDIT: Posting the XAML as requested. The template is literally just the simplest possible thing:
<UserControl.Resources>
<DataTemplate x:Key="HeaderTemplate">
<TextBlock Text="{Binding TabName}" />
</DataTemplate>
</UserControl.Resources>
And then further down the page,
<props:PropertyGrid
SelectedObject="{Binding Value}"
TabHeaderTemplate="{StaticResource HeaderTemplate}" />
But for some bizarre reason, in the template it's trying to interpret the binding inside the wrong DataContext!
In this case, just be sure to specify the source in your binding. There are a few ways to do this. One is to use the RelativeSource property of the Binding. Another is to use ElementName
Give your UserControl this attribute:
x:Name="Root".
Then change your binding to use it
<TextBlock Text="{Binding ElementName=Root, Path=DataContext.TabName}" />
Or use this:
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:MyUserControl}}, Path=DataContext.TabName}"/>
I have created a global font resource in App.xaml like this:
<Application.Resources>
<ResourceDictionary>
<FontFamily x:Key="GlobalFontLight">Arial</FontFamily>
<FontFamily x:Key="GlobalFont">Segoe UI</FontFamily>
<FontFamily x:Key="GlobalFontBold">Caibri</FontFamily>
</ResourceDictionary>
</Application.Resources>
In MainPage I have added a TextBlock:
<TextBlock Text="Some text" FontFamily="{StaticResource GlobalFont}" Foreground="Black"/>
<TextBlock Text="Some text 2" FontFamily="{StaticResource GlobalFontLight}" Foreground="Black"/>
<TextBlock Text="Some text 3" FontFamily="{StaticResource GlobalFontBold}" Foreground="Black"/>
And it is ok, TextBlock use my global font.
Now, I want to change that global font in Application Resources. I have tried next code:
Application.Current.Resources["GlobalFont"] = new FontFamily("Arial");
But nothing happens, TextBlock still use the old font. If I run this code before InitializeComponent(); then it is working as I want, but after that no. Anyone knows what do I do wrong? How to achieve this dynamic change of font?
Because UWP does not support DynamicResource this is quite a problem. The StaticResource and ThemeResource extensions won't save you here, because they are bound only when evaluated and will not update for the already-evaluated properties when the underlying resource changes.
The first option would be to navigate back and navigate to the same page again, so that the controls get reloaded and the resources evaluated anew.
If you want something more dynamic, please check out my answer on this SO question. If you follow that solution, you can create a class implementing INotifyPropertyChanged that will contain a property of type FontFamily, store this instance in a StaticResource and then use binding instead of StaticResource like this:
<TextBlock Text="{Binding Font, Source={StaticResource CustomUISettings}}" />
I want to know is there anyway to put contentpresenter in itemtemplate of an itemscontrol to display my data. I don't want hard code binding like Text="{Binding username}" cause I am building a custom control, I think ContentPresenter is what I want. But after I tried using contentpresenter, it give me stackoverflowexception.
<ItemsControl ItemsSource="{Binding SelectedItems, ElementName=listbox}" DisplayMemberPath={Binding DisplayMemberPath}">
<ItemsControl.ItemPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="Separator" Text=", "/>
<ContentPresenter/>
<!--<TextBlock Text="{Binding username}"/>-->
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
That's my code.
If without those seperator and itemtemplate, I able to display my data by just using the displaymemberpath, but it stack all the name together. I still finding any solution to solve it. I hope you can provide some ideas to do this.
The answer is no, you can't. A ContentPresenter is supposed to be used in a ControlTemplate, not a DataTemplate, so it is not the right control to use. From the linked page on MSDN:
You typically use the ContentPresenter in the ControlTemplate of a ContentControl to specify where the content is to be added.
What you can do alternatively, is to declare a number of DataTemplates in a Resources section (complete with Binding Paths) for different types of data and omit the x:Key directives, eg. do not name them. Also, do not specify one for the ItemsControl.ItemTemplate.
When doing this, WPF will implicitly select the correct DataTemplate for the relevant data type and so you can have different outputs for different data types. See the The DataType Property section of the Data Templating Overview page on MSDN for further explanation of this technique.
Yes, and it works well. Outside of a ContentControl's template, you must bind the Content by hand:
<ContentPresenter Content="{Binding username}"/>
I do this a great deal and it never misbehaves. ContentPresenter seems to be implemented for general use. I wonder if the API docs overstate its relationship to ContentControl.
I found an easier way to solve this problem by using horizontal listbox. Thanks for responses
Background:
I have a ListBox containing items defined by DataTemplates. Right now, if an object in the list has the property IsEditable set to true, the item's property information will be displayed inside of textboxes (via DataTemplate change), instead of textblocks (so the user can edit the content of that list item)
IsEditable is toggled on/off by a button inside of each list item. I have been told that we need to keep the state of all objects consistent, which means I can't just rebind the ItemsSource and lose everything.
Currently, I'm using this to re-render:
this.lbPoints.Dispatcher.Invoke(DispatcherPriority.Render, new Action(() => { }));
Question:
The aforementioned code snippet KIND OF does its job. By "kind of", I mean, it does eventually cause my data to become re-rendered, but only when I scroll to the bottom of the list and then scroll back up to the item i'm trying to re-render.
1) How can I re-render the data immediately without having to scroll around to get it to show up?
The guys commenting are right that you're going about this the wrong way... there is rarely a need to force a ListBox to re-render. You're probably causing yourself some additional grief trying to switch the DataTemplates (although it is possible). Instead of that, think about data binding the TextBox.IsReadOnly property to your IsEditable property:
<TextBox IsReadOnly="{Binding IsEditable}" Text="{Binding Text}" />
Another alternative is to use a BooleanToVisibilityConverter to show a different Grid in your DataTemplate when your IsEditable property is true. Unfortunately, that Converter doesn't have an inverse operation, so you could create an IsNotEditing property to bind to the Grid in the DataTemplate that is originally displayed. I'm not sure if that's clear... see this example:
<DataTemplate DataType="{x:Type YourPrefix:YourDataType}">
<Grid>
<Grid Visibility="{Binding IsNotEditing, Converter={StaticResource
BooleanToVisibilityConverter}}">
<!-- Define your uneditable UI here -->
</Grid>
<Grid Visibility="{Binding IsEditing, Converter={StaticResource
BooleanToVisibilityConverter}}">
<!-- Define your editable UI here -->
</Grid>
</Grid>
</DataTemplate>
You could also define your own BooleanToVisibilityConverter class that has an IsInverted property, so that you can just use the one IsEditing property. You'd need to declare two Converters still, like this:
<Converters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
<Converters:BoolToVisibilityConverter x:Key="InvertedBoolToVisibilityConverter"
IsInverted="True" />
Then your XAML would be like this:
<Grid Visibility="{Binding IsEditing, Converter={StaticResource
InvertedBoolToVisibilityConverter}}">
<!-- Define your uneditable UI here -->
</Grid>
<Grid Visibility="{Binding IsEditing, Converter={StaticResource
BoolToVisibilityConverter}}">
<!-- Define your editable UI here -->
</Grid>
When I add
<TextBlock Text="{Binding SettingName}" TextWrapping="Wrap" Margin="10,-2,10,0" Style="{StaticResource PhoneTextSubtleStyle}" />
Everuthing is ok. But when
<TextBlock x:Name="{Binding SettingTextBlockName}" Text="{Binding SettingName}" TextWrapping="Wrap" Margin="10,-2,10,0" Style="{StaticResource PhoneTextSubtleStyle}" />
constructor are breaking.
But I need different names in all elements.
x:Name is a special property. As a matter of fact it's not a property at all, it's an attribute that maps the name or id property of the element to x:Name. Binding only works when applied to a DependencyProperty, so it cannot work on x:Name. It must be set manually.
If you want to distinguish between objects in runtime, you can set the Tag attribute, which tolerates everything.
more on x:Name: http://msdn.microsoft.com/en-us/library/ms752290.aspx
You should use FrameworkElement.Tag property, according to MSDN
FrameworkElement.Tag gets or sets an arbitrary object value that can
be used to store custom information about this element.
What use is the Tag property in .net