I have a DataTemplateSelector like this:
Public Class TestTemplateSelector
Inherits DataTemplateSelector
Public Property Template1 As DataTemplate
Public Property Template2 As DataTemplate
Public Overrides Function SelectTemplate(item As Object, container As DependencyObject) As DataTemplate
Dim selector As Integer
If (item Is Nothing) OrElse TypeOf item IsNot String Then
Return MyBase.SelectTemplate(item, container)
End If
If Not Integer.TryParse(CType(item, String), selector) Then
Return MyBase.SelectTemplate(item, container)
End If
Select Case selector
Case 1
Return Me.Template1
Case 2
Return Me.Template2
Case Else
Return MyBase.SelectTemplate(item, container)
End Select
End Function
End Class
I define it in the Resources of a Window like this:
<Window.Resources>
<DataTemplate x:Key="Template1">
<TextBox Text="Template 1" />
</DataTemplate>
<DataTemplate x:Key="Template2">
<TextBox Text="Template 2" />
</DataTemplate>
<local:TestTemplateSelector x:Key="sel"
Template1="{StaticResource Template1}"
Template2="{StaticResource Template2}" />
</Window.Resources>
And I use it in the same Window like this:
<ContentControl Margin="5"
Content="2"
ContentTemplateSelector="{StaticResource sel}" />
If I switch the Content of the ContentControl between 1 and 2 it shows the corresponding templates, but I always see a gray border around the ContentControl.
Setting the BorderBrush of the ContentControl to Transparent and/or setting the BorderThickness to 0 doesn't remove the border.
How can I get rid of this border?
Here's a screenshot of the whole window:
There should be no border by default. You may have an implicit Style somewhere that adds it.
Try to set the BorderThickness property to 0:
<ContentControl Margin="5"
BorderThickness="0"
BorderBrush="{x:Null}"
Content="2"
ContentTemplateSelector="{StaticResource sel}" />
Or set the Template property to a ControlTemplate without a Border:
<ContentControl Margin="5"
Content="2"
ContentTemplateSelector="{StaticResource sel}">
<ContentControl.Template>
<ControlTemplate TargetType="{x:Type ContentControl}">
<ContentPresenter/>
</ControlTemplate>
</ContentControl.Template>
</ContentControl>
Related
Solved:
I was an idiot and trusted the editors information that the DataContext is wrong. The solution is simply
<TextBlock Text="{Binding A}" />
I added a TextBlock beneath each displayed Item of a ListView. For this I used a ControlTemplate with the target type set to "ListViewItem". I put the GridViewRowPresenter and the TextBlock into a StackPanel.
<ListView ItemsSource="{Binding Items}">
<ListView.Resources>
<ControlTemplate x:Key="CustomListViewItemTemplate" TargetType='{x:Type ListViewItem}'>
<StackPanel>
<GridViewRowPresenter Content="{TemplateBinding Content}"
Columns="{TemplateBinding GridView.ColumnCollection}"/>
<TextBlock Text="{Binding }" /> <!-- here I fail -->
</StackPanel>
</ControlTemplate>
</ListView.Resources>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Template" Value="{StaticResource CustomListViewItemTemplate}"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
...
</GridView>
</ListView.View>
</ListView>
The ItemsSource of the ListView is a ObservableCollection Items = new ObservableCollection<Item>();
with Item as
public class Item
{
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
}
I can access the ListViewItem in the ControlTemplate, but not the Item itself. Is there a possibility bind the TextBlock in the ControlTemplate to e.g. the Property "A" of each instance of Item?
With <ListView ItemsSource="{Binding Items}"> you specify which collection (In this case Items) provides data for the ListView. Within the template, if you assign the value "{Binding}", you effectively assign an Item from your collection you specified as ItemsSource.
To assign a binding to a property of your Item, you already found the solution
<TextBox Text="{Binding A}"/>
Additionally to your current solution,
<TextBlock Text="{Binding Path=A, Mode=TwoWay}"/>
above syntax allows you to navigate to nested members, and set additional binding related parameters like Mode, UpdateSourceTrigger, Converter etc.
I have a view model for a DataGrid that is like this:
public class Cell
{
public CellValue CellValue { get; }
}
And the CellValue property can be of several types:
public class CellValue
{
public double Value { get; }
}
public class TwoValueCell : CellValue
{
public double Value2 { get; }
}
The DataGrid is binding the ItemsSource to a list of my rows and cells.
The DataGrid binds the data as expected: I get a Cell in each DataGridCell. So I have a style in the resources like this (local resources for now):
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<ContentPresenter x:Name="ContentHost"
Margin="{TemplateBinding Padding}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<DataTemplate DataType="{x:Type viewModel:Cell}">
<Grid>
<TextBlock Text="{Binding CellValue}"/>
</Grid>
</DataTemplate>
</DataGrid.Resources>
I like having the template bound to the view model type ...
The question is: instead of the Binding on the TextBlock, I want to inflate another DataTemplate there which I can somehow define again by specific CellValue Types.
In other words, in psudocode it might look like this:
<DataTemplate DataType="{x:Type viewModel:Cell}">
<Grid>
<DataTemplate DataType="{x:Type viewModel:CellValue}">
<TextBlock Text="{Binding Value}"/>
</DataTemplate>
</Grid>
</DataTemplate>
But I would need to define the specific CellValue data templates somewhere ...
The bottom line is in having one Type for the DataGridCell --- and having a data template for that type --- but then having several specific types on the property of the cell, and I want to define custom data templates based on the actual type of the PROPERTY.
Any help?
You can use ContentControl.
<DataTemplate ...>
<Grid>
<ContentControl DataContext="{Binding SomeProperty}">
<ContentControl.ContentTemplate>
<DataTemplate ...> ... </DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</Grid>
</DataTemplate>
I have a usercontrol which contains an ellipse inside the Canvas. I am using this control in another window and when i set the background color, i want to change only the background of ellipse.How to change the ellipse(child) background without changing canvas(parent) background color?
1. Add a DependencyProperty to the code-behind of your MyUserControl.
Note the 3rd parameter of the Register method is whatever the Type name is of your UserControl
public Brush EllipseFill
{
get { return (Brush)GetValue(EllipseFillProperty); }
set { SetValue(EllipseFillProperty, value); }
}
public static readonly DependencyProperty EllipseFillProperty =
DependencyProperty.Register("EllipseFill", typeof(Brush), typeof(MyUserControl), new PropertyMetadata(null));
2. Add a reference to the xaml file of both the main Window and the UserControl for the namespace where MyUserControl is defined :
xmlns:local="clr-namespace:WpfApplication1"
3. Bind the Fill property of your Ellipse to the dependency property that was defined on MyUserControl.
Note the use of MyUserControl in AncestorType parameter of the RelativeSource binding.
<Viewbox>
<Canvas Width="100" Height="100">
<Ellipse Width="50"
Height="20"
Canvas.Top="50"
Canvas.Left="50"
Fill="{Binding Path=EllipseFill,
RelativeSource= {RelativeSource Mode=FindAncestor,
AncestorType={x:Type local:MyUserControl}}}"
/>
<Rectangle Width="20"
Height="40"
Canvas.Top="10"
Canvas.Left="10"
Fill="Blue"
/>
</Canvas>
</Viewbox>
4. Set the EllipseFill property on MyUserControl in the main Window
<local:MyUserControl EllipseFill="Red"/>
I'm using a WPF Datagrid with DataGridTemplateColumns with comboboxes in each cell. At startup, the output window repeats the following message and delays startup about 10 seconds. Something related to ContentPresenter and DataContext not being set (DataItem=null). Please help if you can. Here is the error message:
System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:(no path); DataItem=null; target element is 'ContentPresenter' (Name=''); target property is 'Content' (type 'Object')
It's not technically an error, but it delays the startup nonetheless. Here is a subset of the xaml:
<DataGrid x:Name="grid"
AutoGenerateColumns="False"
CanUserAddRows="True"
IsEnabled="True" Grid.Row="1" Grid.Column="0"
EnableRowVirtualization="False"
HorizontalAlignment="Left"
VerticalAlignment="Center"
ScrollViewer.CanContentScroll="True"
GridLinesVisibility="Vertical"
AreRowDetailsFrozen="True"
HorizontalScrollBarVisibility="Visible"
VerticalScrollBarVisibility="Visible"
SelectionMode="Extended"
HeadersVisibility="All"
Height="750"
VirtualizingStackPanel.VirtualizationMode="Standard"
VirtualizingStackPanel.IsVirtualizing="True"
DataContext="{StaticResource vm}"
ItemsSource="{Binding Source={StaticResource vm}, Path=CorpActionAutoPostConfigs, Mode=TwoWay, IsAsync=False}">
<DataGrid.Columns>
<!-- selecteditembinding: source:enum, dest:JournalType -->
<DataGridTemplateColumn Header="JournalType" x:Name="colJournalType">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox x:Name="cbJournalTypes"
ItemsSource="{Binding Source={StaticResource vm}, Path=JournalTypes, IsAsync=False}"
ItemTemplate="{StaticResource GenericDataTemplate}"
SelectedItem="{Binding Path=JournalTypeCode, Mode=TwoWay, Converter={StaticResource JournalTypeConverter}, IsAsync=False}">
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
...more similar columns follow. I feel like I need to set a Style or ControlTemplate or something but not exactly sure how to proceed.
If I use a ListView/GridView structure, these "errors" do not occur and startup is much faster. But I would prefer to use the DataGrid.
One clue is it seems I get that error for each visible cell that is generated. So I tried to define a style for DataGridCell, that sets the control template for each cell and includes a ContentPresenter binding with a fallback value. Did not resolve the errors.
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="DataGridCell" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Border BorderThickness="{TemplateBinding Border.BorderThickness}"
BorderBrush="{TemplateBinding Border.BorderBrush}"
Background="{TemplateBinding Panel.Background}"
SnapsToDevicePixels="True">
<ContentPresenter x:Name="DataGridCellContentPresenter"
Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content, FallbackValue=null}"
ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}"
ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}"
SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
EDIT:
Looking at the Visual Tree, it seems the ContentPresenter I have defined in the ControlTemplate contains yet another ContentPresenter. That ContentPresenter is nameless and I suspect is the source of the binding errors. The parent of that ContentPresenter is the Border. Does anyone know how to define this ContentPresenter in a ControlTemplate so I can add a fallback value?
I can't yet add a screencap of the visual tree, but here is what it looks like:
DataGridCell
ContentPresenter (name=DataGridCellPresenter)
ContentPresenter (unnamed, Border is parent)
A little late to the party, but I managed a work around for this issue - if derive your own custom class from DataGridTemplateColumn you can explicitly set the FallbackValue for the Binding.
Obviously you then have to go through the XAML and replace the required elements.
public sealed class DataGridTemplateColumnEx : DataGridTemplateColumn
{
protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
{
return LoadTemplateContent(false, dataItem, cell);
}
protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
{
return LoadTemplateContent(true, dataItem, cell);
}
private void ChooseCellTemplateAndSelector(bool isEditing, out DataTemplate template, out DataTemplateSelector templateSelector)
{
template = null;
templateSelector = null;
if (isEditing)
{
template = CellEditingTemplate;
templateSelector = CellEditingTemplateSelector;
}
if (template == null && templateSelector == null)
{
template = CellTemplate;
templateSelector = CellTemplateSelector;
}
}
private FrameworkElement LoadTemplateContent(bool isEditing, object dataItem, DataGridCell cell)
{
ChooseCellTemplateAndSelector(isEditing, out var template, out var templateSelector);
if (template != null || templateSelector != null)
{
var contentPresenter = new ContentPresenter();
var binding = new Binding
{
// Explicitly setting this to NULL, stops the binding FallbackValue messages, and therefore improves perf...
FallbackValue = null
};
BindingOperations.SetBinding(contentPresenter, ContentPresenter.ContentProperty, binding);
contentPresenter.ContentTemplate = template;
contentPresenter.ContentTemplateSelector = templateSelector;
return contentPresenter;
}
return null;
}
}
As titled,
I seen couples of similiar question this or this in SO, but I don't see a solution for it.
I know if I need to bind to the code-beind, I need to set Datacontext = this
But my problem is that my datacontext already binding to my ViewModel, but I want to do some UI manipulation with using Command which is defined in the code-beind.
Is it possbile to bind it in xaml? If so, how?
EDIT: I did tried the follows:
<Window x:Class="WpfApplication3.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" x:Name="_Root">
<Grid x:Name="hellogrid">
<TextBlock x:Name="myTextBlock" Text="AAAA"/>
<Button Margin="82,119,121,120" Name="button2" Content="{Binding Path=Text, ElementName=myTextBlock}"/>
<Button Margin="82,72,121,0" Name="button3" Content="{Binding Path=MyText, ElementName=_Root}" Height="23" VerticalAlignment="Top" />
</Grid>
And code-behind:
public partial class Window1 : Window
{
public string MyText { get; set; }
public Window1()
{
InitializeComponent();
MyText = "ABC";
}
}
I could see the Button2 shows AAAA, but Button3 shows nothing....
Of course
There are many types of bindings. The most basic one binds to a property on the DataContext, which is usually inherited from a Parent object
<DataTemplate DataType="{x:Type MyModel}">
<!-- DataContext is object of type MyModel -->
<local:MyView />
</DataTemplate>
Or
<Window x:Name="MyWindow">
<!-- DataContext Inherited from Window -->
<TextBlock Text="{Binding SomeProperty}" />
</Window>
where
var SomeObject = new SomeModel();
SomeObject.SomeProperty = "Test";
myWindow.DataContext = SomeObject;
Other binding types include ElementName, where you can specify the target UI element to use as the data source for the binding
<StackPanel>
<CheckBox x:Name="SomeCheckBox" />
<TextBlock Text="{Binding ElementName=SomeCheckBox, Path=IsChecked}" />
</StackPanel>
or
<local:MyUserControl x:Name="SomeUserControl">
<Button Command="{Binding ElementName=SomeUserControl, Path=DataContext.SaveCommand}" />
</local:MyUserControl >
Or RelativeSource, which allows you to find an object relative to the current object to use as a DataSource
<Window Title="Test">
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=Title}" />
</Window>
or
<local:MyUserControl>
<Button Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:MyUserControl}}, Path=DataContext.SaveCommand}" />
</local:MyUserControl >
And TemplateBinding, which binds is a shortcut to a RelativeSource binding that binds to a templated object
<Button Content="Test">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<TextBlock Text="{TemplateBinding Content}" />
</ControlTemplate>
</Button.Template>
</Button>
EDIT
The best solution IMO is the one posted by #Saad Imran in this SO question...
With this solution all you have to do is name your window and binding to a property in your XAML will be as easy as this {Binding ElementName=MyWindowName, Path=MyText}
So, what you are doing with Content="{Binding Path=MyText, ElementName=_Root}" is exactly right and your Button Content property IS bound to MyText property but the only thing you are missing is change notification (need to implement INotifyPropertyChanged interface for that) so when you set your MyText property to ABC MyText = "ABC"; no change notification is sent...
Easy way to test this is by setting the MyText property explicitly as such:
private string myText = "ABC";
public string MyText
{
get { return myText; }
set { myText = value; }
}
or setting it in the constructor before InitializeComponent() is called:
MyText = "ABC";
InitializeComponent();
If you do that you'll notice that your button will have ABC as its content but changes to MyText property will not affect the button content because there is no change notification...
Sure, you can use ElementName:
<Window Name="root"
Class="..."
...>
...
<TextBox Text="{Binding Path=Foo, ElementName=root}" />
You could also do it with RelativeSource, but the syntax is uglier...