I'm having trouble getting the autocomplete box in System.Windows.Controls.Input working as I wish. When I start typing the dropdown section that displays the filtered list doesn't show the property that I'm binding to, it shows the class name instead.
So in the example below, when I type in my - instead of showing 'My Name' it shows MyNamespace.Person. However, when I select the item from the autocomplete list, it displays the FullName property in the textbox. I'm sure I'm just missing a simple autocomplete box property somewhere but I can't see it.
Example code:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName
{
get { return string.Format("{0} {1}", FirstName, LastName); }
}
}
In my xaml code behind I create some Person objects and store them in a list and bind that list to an autocomplete box
List<Person> people = new List<Person>();
people.Add(new Person { FirstName = "My", LastName = "Name" });
people.Add(new Person { FirstName = "Fernando", LastName = "Torres" });
acbNames.ItemsSource = people;
My xaml:
<my:AutoCompleteBox Name="acbNames" ValueMemberPath="FullName" />
/* after entering 'my', auto complete displays 'MyNamespace.Person' instead of 'My Name', but displays 'My Name' after selecting the item from the list */
It turns out I need to use an ItemTemplate for the dropdown part of the AutoCompleteBox, so the xaml for it would now be as follows:
<my:AutoCompleteBox Name="acbNames" ValueMemberBinding="{Binding FullName}">
<my:AutoCompleteBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding FullName}"/>
</DataTemplate>
</my:AutoCompleteBox.ItemTemplate>
</my:AutoCompleteBox>
Yes, your problem was because you didn't put item template.
But if you put item template and still got problem read what Sandro has wroted.
I had same problem. I solved it using a Static resource for the Control Style
This is the style i used:
<Style x:Key="autocomplete" TargetType="sdk1:AutoCompleteBox">
<Setter Property="Margin" Value="5,0,5,0"/>
<Setter Property="MinWidth" Value="100"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property ="HorizontalAlignment" Value="Right"/>
</Style>
If I don't use this style my Customs Item are not displayed correctly as I configure in DataItem, instead it show the Class name.
share|edit
This works for me too but only when i applied some custom theme style from toolkit.
There are some other workarounds when you use theme from toolkit
Best,
debarisi
I had same problem. I solved it using a Static resource for the Control Style
This is the style i used:
<Style x:Key="autocomplete" TargetType="sdk1:AutoCompleteBox">
<Setter Property="Margin" Value="5,0,5,0"/>
<Setter Property="MinWidth" Value="100"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property ="HorizontalAlignment" Value="Right"/>
</Style>
If I don't use this style my Customs Item are not displayed correctly as I configure in DataItem, instead it show the Class name.
Related
Good evening. A WFP binding question please.
Let's say that I have the following three classes:
public class Field
{
public string Data {get; set; }
public string TooltipText {get; set; }
public Field(string data, string tttext)
{
Data = data;
TooltipText = tttext;
}
}
public class FName : Field
{
public FName()
: base("","Enter first name")
{
}
}
public class Person
{
public FName FirstName {get; set; }
}
In XAML, assuming I have set the data context to Person in code, I can bind a TextBox's text and tooltip by
<TextBox Text="{Binding FirstName.Data, Mode=TwoWay}" Tooltip={Binding FirstName.TooltipText}" />
Is there a way to do this generically (if that's the first word) by referencing the base class' properties in a style so that I do not need to declare it for every TextBox? For instance, as a mockup:
<TextBox Binding="FirstName" Style="{StaticResource TextBoxStyle}">
and the style is something like
<Style x:Key="TextBoxStyle" TargetStyle="TextBox">
<Setter Property="Text" Value="{Binding Field.Data, Mode=TwoWay}" />
<Setter Property="Tooltip" Value="{Binding Field.TooltipText}" />
</Style>
All of my input fields are derived from a base class and it would be nice for the binding of data and tooltips to occur automatically from the Style.
Thank you in advance for any knowledge and/or help along these lines.
What you've posted will work fine, just bind directly to Data and TooltipText instead of Field.Data and Field.TooltipText.
I found the answer, which is exactly what you replied! I just need to set the DataContext to FieldName and now it all works perfectly.
<TextBox Style="{StaticResource TextBoxStyle}" DataContext={Binding FirstName}">
This data-binding stuff is so cool.
Thanks again for the help!
I tried to create a Style for DataGridTextColumn with the following code
<Style TargetType="{x:Type DataGridTextColumn}">
...
</Style>
However, Visual Studio 2010 highlights {x:Type DataGridTextColumn} with a blue line and elaborates: Exception has been thrown by the target of an invocation.
Why does this happen and how do I fix it?
You can't style the DataGridTextColumn because DataGridTextColumn does not derive from FrameworkElement (or FrameworkContentElement). Only FrameworkElement, etc supports styling.
When you attempt to create a style in XAML for any type that is not a FrameworkElement or FrameworkContentElement you get that error message.
How do you solve this? As with any problem, where there is a will there is a way. In this case I think the easiest solution is to create an attached property for DataGrid to assign a DataGridColumn style:
<DataGrid ...>
<local:MyDataGridHelper.TextColumnStyle>
<Style TargetType="FrameworkElement">
... setters here ...
</Style>
</local:MyDataGridHelper.TextColumnStyle>
...
The implementation would be something along these lines:
public class MyDataGridHelper : DependencyObject
{
// Use propa snipped to create attached TextColumnStyle with metadata:
... RegisterAttached("TextColumnStyle", typeof(Style), typeof(MyDataGridHelper), new PropertyMetadata
{
PropertyChangedCallback = (obj, e) =>
{
var grid = (DataGrid)obj;
if(e.OldValue==null && e.NewValue!=null)
grid.Columns.CollectionChanged += (obj2, e2) =>
{
UpdateColumnStyles(grid);
}
}
}
private void UpdateStyles(DataGrid grid)
{
var style = GetTextColumnStyle(grid);
foreach(var column in grid.Columns.OfType<DataGridTextColumn>())
foreach(var setter in style.Setters.OfType<Setter>())
if(setter.Value is BindingBase)
BindingOperations.SetBinding(column, setter.Property, setter.Value);
else
column.SetValue(setter.Property, setter.Value);
}
}
The way this works is, any time the attached property is changed, a handler is added for the Columns.CollectionChanged event on the grid. When the CollectionChanged event fires, all columns are updated with the style that was set.
Note that the above code does not handle the situation where a style is removed and re-added gracefully: Two event handlers are registered. For a really robust solution you would want to fix this by adding another attached property containing the event handler so the event handler could be unregistered, but for your purpose I think this is unimportant.
Another caveat here is that the direct use of SetBinding and SetValue will cause the DependencyProperty to have a BaseValueSource of Local instead of DefaultStyle. This will probably make no difference in your case but I thought I should mention it.
The style tag has to go in the right place. Your datagrid may look something like this right now:
<DataGrid>
<DataGrid.Columns>
<DataGridTextColumn />
</DataGrid.Columns>
</DataGrid>
You might initially try to add the style tag directly within the DataGridTextColumn element which will not work. You can however create elements for "DataGridTextColumn.ElementStyle" and or "DataGridTextColumn.EditingElementStyle" just within the "DataGridTextColumn" element. Each of those element tags can then have style tags within them:
<DataGrid>
<DataGrid.Columns>
<DataGridTextColumn>
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="Background" Value="Green"></Setter>
</Style>
</DataGridTextColumn.ElementStyle>
<DataGridTextColumn.EditingElementStyle>
<Style TargetType="TextBox">
<Setter Property="Background" Value="Orange"></Setter>
</Style>
</DataGridTextColumn.EditingElementStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
One style will be applied to viewing and the other will be applied when the cell is in edit mode. Note that it changes from a TextBlock when viewing to a TextBox when editing (This got me at first!).
This is more an addition to Ray Burns answer. I first wasn't able to implement it on my own, but with help of mm8 (https://stackoverflow.com/a/46690951/5381620) I got it running. Works really fine. For other people who have problems following this attached property approach maybe a full code snippet is helpful.
public class MyDataGridHelper : DependencyObject
{
private static readonly DependencyProperty TextColumnStyleProperty = DependencyProperty.RegisterAttached("TextColumnStyle", typeof(Style), typeof(MyDataGridHelper), new PropertyMetadata
{
PropertyChangedCallback = (obj, e) =>
{
var grid = (DataGrid)obj;
if (e.OldValue == null && e.NewValue != null)
grid.Columns.CollectionChanged += (obj2, e2) =>
{
UpdateColumnStyles(grid);
};
}
});
public static void SetTextColumnStyle(DependencyObject element, Style value)
{
element.SetValue(TextColumnStyleProperty, value);
}
public static Style GetTextColumnStyle(DependencyObject element)
{
return (Style)element.GetValue(TextColumnStyleProperty);
}
private static void UpdateColumnStyles(DataGrid grid)
{
var origStyle = GetTextColumnStyle(grid);
foreach (var column in grid.Columns.OfType<DataGridTextColumn>())
{
//may not add setters to a style which is already in use
//therefore we need to create a new style merging
//original style with setters from attached property
var newStyle = new Style();
newStyle.BasedOn = column.ElementStyle;
newStyle.TargetType = origStyle.TargetType;
foreach (var setter in origStyle.Setters.OfType<Setter>())
{
newStyle.Setters.Add(setter);
}
column.ElementStyle = newStyle;
}
}
}
xaml
<Grid>
<DataGrid Name="MyDataGrid" ItemsSource="{Binding Lines}" AutoGenerateColumns="False" >
<local:MyDataGridHelper.TextColumnStyle>
<Style TargetType="TextBlock">
<Setter Property="TextWrapping" Value="Wrap"/>
</Style>
</local:MyDataGridHelper.TextColumnStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="ProductId1" Binding="{Binding Path=Result1}" />
<DataGridTextColumn Header="ProductId2" Binding="{Binding Path=Result2}" />
</DataGrid.Columns>
</DataGrid>
</Grid>
Edit: In first approach I did overwrite the whole style. In new version it is still possible to maintain other styles modifications like this one
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="Red"/>
</Style>
</DataGridTextColumn.ElementStyle>
A small addition to pedrito answer. Everything works fine, but if origStyle has base style, base style's setters get discarded.
To fix this, we need get all setters:
private static void UpdateColumnStyles(DataGrid grid)
{
var origStyle = GetTextColumnStyle(grid);
foreach (var column in grid.Columns.OfType<DataGridTextColumn>())
{
//may not add setters to a style which is already in use
//therefore we need to create a new style merging
//original style with setters from attached property
var newStyle = new Style();
newStyle.BasedOn = column.ElementStyle;
newStyle.TargetType = origStyle.TargetType;
var baseSetters = GetBaseSetters(origStyle);
var allSetters = baseSetters.Concat(origStyle.Setters.OfType<Setter>());
foreach (var setter in allSetters)
{
newStyle.Setters.Add(setter);
}
column.ElementStyle = newStyle;
}
}
private static IEnumerable<Setter> GetBaseSetters(Style style)
{
return style.BasedOn?.Setters.OfType<Setter>().Concat(GetBaseSetters(style.BasedOn)??new Setter[0]);
}
More simple:
<FontFamily x:Key="DefaultFont">Snap ITC</FontFamily>
<Style x:Key="ControlStyle" TargetType="Control">
<Setter Property="FontFamily" Value="{StaticResource DefaultFont}"/>
</Style>
<Style TargetType="{x:Type DataGridCellsPresenter}" BasedOn="{StaticResource ControlStyle}">
</Style>
A DataGridTextColumn is nothing but a column with a TextBlock in it. Write a style with the TargetType as TextBlock and bind the ElementStyle property of the DataGridTextColumn to it. Hope that helps!
My user control have the following DP:
public static readonly DependencyProperty ButtonAnimationColorProperty =
DependencyProperty.Register("ButtonAnimationColor", typeof(Color), typeof(MyControl),
new FrameworkPropertyMetadata(Colors.RoyalBlue, FrameworkPropertyMetadataOptions.AffectsRender, ThemeUpdate));
public Color ButtonAnimationColor
{
get { return (Color)GetValue(ButtonAnimationColorProperty ); }
set { SetValue(ButtonAnimationColorProperty , value); }
}
This control is compiled into a dll, that I use in others solutions. It works perfect well when I set directly:
<ns:MyControl ButtonAnimationColor="Green" />
The problem occurs when I try to set this DP by using a Style Setter, like that:
<ns:MyControl>
<ns:MyControl.Style>
<Style>
<Setter Property="ButtonAnimationColor" Value="Green" />
</Style>
</ns:MyControl.Style>
</ns:MyControl>
It give me the following error:
The member "ButtoAnimationColor" is not recognized or is not acessible.
What changes I need to make in my code to be able to set the property like that?
Try setting the target type for the style:
<ns:MyControl.Style>
<Style TargetType="{x:Type ns:MyControl}">
<Setter Property="ButtonAnimationColor" Value="Green" />
</Style>
</ns:MyControl.Style>
I am new at WPF and of course I faced some issues with Bindings.
I have initialized RadCartesianChart and I want display data from different type of category lists. For each of those lists I want different color, but I fail to Bind Fill property to my Color property in code behind.
This is how my XAML looks like:
<telerik:RadCartesianChart Name="RevChart">
<telerik:RadCartesianChart.Grid>
<telerik:CartesianChartGrid MajorYLineDashArray="5, 5" MajorLinesVisibility="Y">
<telerik:CartesianChartGrid.MajorYLineStyle>
<Style TargetType="{x:Type Line}">
<Setter Property="Stroke" Value="Gray"/>
</Style>
</telerik:CartesianChartGrid.MajorYLineStyle>
</telerik:CartesianChartGrid>
</telerik:RadCartesianChart.Grid>
<telerik:RadCartesianChart.HorizontalAxis>
<telerik:CategoricalAxis />
</telerik:RadCartesianChart.HorizontalAxis>
<telerik:RadCartesianChart.VerticalAxis>
<telerik:LinearAxis/>
</telerik:RadCartesianChart.VerticalAxis>
<telerik:AreaSeries CategoryBinding="Date" ValueBinding="Rev" Fill="{Binding Color}">
</telerik:AreaSeries>
</telerik:RadCartesianChart>
This is my C# code:
public class Revenue
{
public double Rev { get; set; }
public DateTime Date { get; set; }
public Color Color { get; set; }
}
List<Revenue> list = new List<Revenue>();
...
...
this.RevChart.Series[0].ItemsSource = list;
As a results I am getting correct picture, but color is default. So my binding of Color doesn't work. Is it problem in this line Fill={Binding Color} ? Why?
Its because Fill is a Brush and you are trying to assign a Color, this wont work.
You will have to assign your Color to the Color property of a SolidColorBrush in the Fill property.
Example
<telerik:AreaSeries CategoryBinding="Date" ValueBinding="Rev">
<telerik:AreaSeries.Fill>
<SolidColorBrush Color="{Binding Color}" />
</telerik:AreaSeries.Fill>
</telerik:AreaSeries>
I have a WPF CustomControl that is derived from ComboBox and I'm trying to figure out how to customize the display of the items. Basically, I want most items to show with normal text but,
depending on the data in each item object, I would like some to display either bold or italic. Normally I do this directly in the XAML, but since it's a CustomControl I'm a bit at a loss. I would love to be able to just bind it directly in code, but I'm also open to methods that might mean loading in external XAML styles, if you can show me how to do that (I haven't a clue).
The code below is a basic approximation of the control I'm using but greatly simplified. However, the basic concept of how the data loaded is the same and the data objects themselves are coming from an external source so they can not access the control itself in anyway. The template needs to
just be bound off of the base properties.
public class FormatData
{
public FormatData() { }
public string Name { get; set; }
public bool Bold { get; set; }
public bool Italic { get; set; }
}
public class FormatDropDown : System.Windows.Controls.ComboBox
{
public FormatDropDown()
{
}
public void LoadSelection(FormatData[] data)
{
try
{
this.ItemsSource = data;
this.DisplayMemberPath = "Name";
}
catch (Exception e) { MessageBox.Show(e.Message); ; }
}
}
The control is populated as follows:
var data = new FormatData[]{
new FormatData(){
Name = "Normal"
},
new FormatData(){
Name = "Bold",
Bold = true
},
new FormatData(){
Name = "Italic",
Italic = true
},
new FormatData(){
Name = "BoldItalic",
Bold = true,
Italic = true
},
};
fddTest.LoadSelection(data);
Anyone have an idea of how I can achieve this?
How about this:
public class FormatDropDown : System.Windows.Controls.ComboBox {
static FormatDropDown() {
DefaultStyleKeyProperty.OverrideMetadata(typeof(FormatDropDown), new FrameworkPropertyMetadata(typeof(FormatDropDown)));
}
public void LoadSelection(FormatData[] data) {
try {
this.ItemsSource = data;
this.DisplayMemberPath = "Name";
} catch (Exception e) { MessageBox.Show(e.Message); ; }
}
}
And in the theme file (generic.xaml):
<Style TargetType="{x:Type local:FormatDropDown}" BasedOn="{StaticResource {x:Type ComboBox}}">
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="ComboBoxItem">
<Style.Triggers>
<DataTrigger Binding="{Binding Bold}" Value="True">
<Setter Property="FontWeight" Value="Bold" />
</DataTrigger>
<DataTrigger Binding="{Binding Italic}" Value="True">
<Setter Property="FontStyle" Value="Italic" />
</DataTrigger>
</Style.Triggers>
</Style>
</Setter.Value>
</Setter>
</Style>
So essentially override the DefaultStyleKey for your custom control.