This page is a listing of WPF and XAML development tips.
A: In WPF, you cannot bind to a variable, only to a property.
1. Set a DataContext for this window or user control. Data binding is done to whatever the DataContext property is set equal to. This can be done in two ways:
a. In the View constructor (.xaml.cs), manually assign it in code
this.DataContext = <some object>
b. Assign the DataContext via XAML. This can be done in several ways.
i. Within the UserControl block, add a UserControl.DataContext element, for example:
<UserControl.DataContext>
<Binding Source="{StaticResource ViewModel}" />
</UserControl.DataContext>
2. In WPF, binding occurs to members of the DataContext. If the property you wish to bind to is not a member of the DataContext, or member of a member, you can't bind to it.
3. Set the Text attribute of the XAML for this control to reference the member of the DataContext to bind for display. For example, assume DataContext is equal to a class with a public member called CurrentContainerPath. To bind to dataContext.CurrentContainerPath, set or change the Text attribute as follows:
Text="{Binding Path=CurrentContainerPath}"
A: When the member changes, you must call RaisePropertyChanged with the name of the member. This means that practically, the member must be a property. Also, the DataContext, the object containing the property, must implement System.ComponentModel.INotifyPropertyChanged.
A: This is due to the design of ObservableCollection. To resolve this, suppress the collection changed notifications generated when each item is added. There are two ways to do this:
1. Switch to a System.ComponentModel.BindingList and suppress list change notifications by setting RaiseListChangedEvents = false before adding them items.
2. Create a new class derrived from IObservableCollection with a new AddBulk member and overriding OnCollectionChanged. In AddBulk, set a flag indicating that AddBulk is being called. In OnCollectionChanged, do not call base.OnCollectionChanged if that flag is set.
See this article for more information: http://stackoverflow.com/questions/57020/which-net-collection-for-adding-multiple-objects-at-once-and-getting-notified
A: Follow these steps:
1. Add the following to the Window or User control element at the root of the XAML:
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
2. Find the XAML binding that you are having trouble with and set it's TraceLevel=high by adding diag:PresentationTraceSources.TraceLevel=High to the binding spec. For example:
<t:DataGridTextColumn Header="Filename" Width="250" Binding="{Binding Path=name, diag:PresentationTraceSources.TraceLevel=High}"/>
3. Build and run your application. The binding log messages will appear in the Output window. Messages indicating "got raw value {DependencyProperty.UnsetValue}" mean the source property is null. It may not have been set before InitializeComponents was called.
If this is a Release-mode application that you cannot run under a debugger, enable trace logging by editing the app.config of your EXE and adding the following within the configuration block. The trace filename is specified via system.diagnostics\sharedListeners\add.initializeData attribute, c:\Debug.txt in this case.
<system.diagnostics>
<sources>
<source name="System.Windows.Data" switchName="SourceSwitch" >
<listeners>
<add name="textListener" />
</listeners>
</source>
</sources>
<switches>
<add name="SourceSwitch" value="All" />
</switches>
<sharedListeners>
<add name="textListener"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="c:\\DebugTrace.txt" />
</sharedListeners>
<trace autoflush="true" indentsize="4"></trace>
</system.diagnostics>
Other tricks:
1. Put a breakpoint in the property getter
2. Create a value converter that simply returns the value it was given, then use it in a particular binding of interest and put a breakpoint in the converter.
A: If you are sure the Binding syntax is correct, most likely you are referring to a data member of an object instead of a Property. WPF requires properties. To verify this, enable WPF binding tracing as shown above, then check the trace file for a message like this:
System.Windows.Data Error: 39 : BindingExpression path error: 'name' property not found on 'object' ''MyItemClass' (HashCode=25292115)'. BindingExpression:Path=name; DataItem='MyItemClass' (HashCode=25292115); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
This message illustrates a binding failure because the target is a data member and not a property. Also, note that WPF cannot bind to private properties.
A: There are two ways to do this: via an IValueConverter object, the most powerful way, and via the StringFormat Binding option, new in NET 3.5 SP1. The later is appropriate to most simple cases.
For the IValueConverter approach, you must write an IValueConverter to convert your class to text, then declare the converter in the XAML, and hook it up to the binding.
To declare the converter in the XAML, add it to the Resources as a v: type with an x:Key equal to the name of your class. The v: key may also need to be the same as the class name. For example:
<UserControl.Resources>
<v:HideOnEmptyConverter x:Key="HideOnEmptyConverter" />
To hookup the converter, refer to the XAML static resource in the Binding attribute of your tag. In this example, the entire DataContext object is passed in, not a member of it.
<TextBlock Text="{Binding Converter={StaticResource TagDescriptionConverter}}" Margin="4 0">
The IValueConverter only needs to implement Convert. ConvertBack can do nothing. In Convert, check the type of the object and return your custom string representation, like this:
public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
{
Repository.Interface.Tag valueAsTag;
if (value is Repository.Interface.Tag)
{
valueAsTag = (Repository.Interface.Tag) value;
return String.Format("{0}={1},", valueAsTag.Name, valueAsTag.Value);
}
else
{
return "";
}
A: There are two ways to do this:
1. Write a value converter. See the above question "In WPF, how do I create a custom text display of a bound object?" for how.
2. Use the StringFormat Binding option, new to NET 3.5SP1.
A: Append StringFormat=N0 to your Binding string, as in:
Binding="{Binding Info.Size, StringFormat=N0}"
A: There are two ways to do so: via XAML automatic support and custom sorting. To implement custom sorting:
1. In the DataGrid XAML, set CanUserSortColumns="True"
2. In the column XAML, set CanUserSort="True" for each column where sorting can be done.
3. Write a model/ViewModel function to sort the collection the DataGrid is bound to and set a default for sorting (none/asc/desc).
4. Write a function to respond to clicks on the DataGrid's column headers and request sorting. This function must:
a. Set eventArgs.Handled = true
b. Set the SortDirection for the column. WPF does not automatically set the sort direction when the column is clicked, or change directions. eventArgs.Column is a reference to the column itself, so use eventArgs.Column.SortDirection to get/set this.
c. Note that SortDirection is nullable since a column may not have a sort direction set. Sorting thus can be three state. If you do not want three state sorting, set a default SortDirection on each column in the XAML via SortDirection.
d. Finally, it must call the model/viewmodel sort function created in step 3.
5. On the DataGrid, set Sorting="<name of GUI handler function from #4>" This hooks up the standard click-on-column-header-to-sort UI.
A: Implement the following custom converter, declare it in XAML and use it in the binding to your numeric value. See this question for how to make the two XAML support changes.
class FileSizeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string[] units = { "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
double size = (long)value;
int unit = 0;
while (size >= 1024)
{
size /= 1024;
++unit;
}
return String.Format("{0:0.#} {1}", size, units[unit]);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
A: Use the StringFormat option. {0} refers to the string value of this field.
If your format string starts with {0}, you must start it in one of two ways, or WPF will reject it.
1. Start the string with {}, as in: (RECOMMENDED)
<TextBlock Text="{Binding Info.Size, StringFormat={}{0} bytes}" />
2. An opening parenthesis, as in:
<TextBlock Text="{Binding Info.Size, StringFormat=({0} bytes}" />
If the format starts with the string literal, just enter it directly, as in:
<TextBlock Text="{Binding Info.Size, StringFormat=The size is {0} bytes}" />
A: Specify the Text element using a MultiBinding. For example:
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="({0}, {1:N0} bytes">
<Binding Path="RepositoryFullPathname" Mode="OneWay"/>
<Binding Path="Info.Size" Mode="OneWay"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
A: Set the TextBlock.TextAlignment attribute of the Column's CellStyle using a Style tag. For example:
<t:DataGridTextColumn.CellStyle>
<Style>
<Setter Property="TextBlock.TextAlignment" Value="Right"/>
</Style>
</t:DataGridTextColumn.CellStyle>
A: WPF is built with the assumption that the GUI will not need to update during event handlers. A straightforward way to resolve this is to split your logic at UI update boundaries, then post callbacks to complete the next logical action by using a DispatcherFrame that runs *on idle*. Use a dispatcher *on a GUI object* for this to work. For example, say you want to hide one control and show another during a time-consuming operation, then switch then back on completion. Divide the logic at the hide/show. The hide/show goes in the normal view event handler, and the time-consuming operation and switch back go in a Dispatch
private void OnAddTagClick(object sender, RoutedEventArgs e)
{
entityGrid.Visibility = System.Windows.Visibility.Collapsed;
waitForSearch.Visibility = System.Windows.Visibility.Visible;
entityGrid.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.ApplicationIdle, new GuiWorker(AddFilterTagWorker));
}
public delegate void GuiWorker();
public void AddFilterTagWorker()
{
viewModel.AddFilterTag(tagBox.Text);
waitForSearch.Visibility = System.Windows.Visibility.Collapsed;
entityGrid.Visibility = System.Windows.Visibility.Visible;
}
If you schedule the worker to run at Normal priority, the GUI will not update until the time-consuming AddFilterTag call completes.
This can also be resolved with two other methods not detailed here: dispatcher frames and forced GUI updates.
See also, possible alternate non-cannon solution: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/6fce9b7b-4a13-4c8d-8c3e-562667851baa/
And one other potential solution that is canon: http://geekswithblogs.net/NewThingsILearned/archive/2008/08/25/refresh--update-wpf-controls.aspx
A: Use these steps:
1. Add a MouseDoubleClick handler to the DataGrid
2. In the event handler, use ContainerFromElement to map the click to the row clicked on, as this handler will receive *all* DataGrid double-clicks, including those in empty space, borders, and the headers. For example:
private void DataGrid_MouseDoubleClick( object sender, MouseButtonEventArgs e )
{
Microsoft.Windows.Controls.DataGridRow gridRow = null;
Repository.Interface.Entity rowEntity = null;
// Did the user double click on a row?
gridRow = ItemsControl.ContainerFromElement((Microsoft.Windows.Controls.DataGrid) sender, e.OriginalSource as DependencyObject) as Microsoft.Windows.Controls.DataGridRow;
if (gridRow != null)
{
rowEntity = gridRow.Item as Repository.Interface.Entity;
// Do something useful with rowEntity
}
A: This is supported through the DataGridTemplateColumn, but not well documented. If the image can be determined by a boolean field, use the following example column definition. In this example, the Item type has a boolean field named "Exists" and the image is stored in another assembly.
<t:DataGridTemplateColumn Header="Icon" Width="50" CanUserResize="False" CanUserSort="False">
<t:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Name="img" Width="16" Height="16"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Exists}" Value="true">
<Setter TargetName="img" Property="Source" Value="/Common;component/Resources/ButtonIcons/folderClosed.png"/>
</DataTrigger>
<DataTrigger Binding="{Binding Exists}" Value="false">
<Setter TargetName="img" Property="Source" Value="/Common;component/Resources/ButtonIcons/documents.png"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</t:DataGridTemplateColumn.CellTemplate>
</t:DataGridTemplateColumn>
A: Use the Image element with the full pathname to the file. If not specified, width and height are extracted from the size of the image resource. This example shows an image where the file exists in another assembly called Common. Note that in such a case, the path prefix "component/" is required to resolve resources in the root of the specified assembly.
<Image Source="/Common;component/Resources/ButtonIcons/folderClosed.png" Width="16" Height="16"></Image>
A: Get the control's binding expression, then call Update target. This requires access to the dependency property. For example:
var bindingExpression = uiTextBlock.GetBindingExpression(TextBlock.TextProperty);
bindingExpression.UpdateTarget();
A: Set DataContext = this in the class constructor and write bindings as you normally would.
A: For example, say your DataContext has a property named Tags with fields Name and Value. To display them both in a single ListBox item, use the following XAML. The Grid element is unnecessary.
<ListBox Grid.Row="1" ItemsSource="{Binding Tags}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Value}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListBox>
A: If the ListBox is single select, use .SelectedItem. Otherwise, you must query each ListBox item. See http://blogs.msdn.com/b/andrewarnottms/archive/2007/09/05/how-to-find-the-focused-listboxitem-in-wpf.aspx for how. For multi-select, if the ListBox does not have focus, this method may not work.
A: Bind the button to the item, then cast the sender object in the event handler to the appropriate control type and use the DataContext. For example:
XAML:
<Button Click="OnDeleteTag" DataContext="{Binding}">
Event handler (OnDeleteTag here):
var senderControl = sender as System.Windows.Controls.Button;
var targetTag = senderControl.DataContext as Repository.Interface.Tag;
A: The assembly backing the control does not exist or can't be built. Review the build output for a warning on the assembly hosting this control or a dependant one that it lacks a reference to a dependent assembly, then add it to the relevant assembly and the build should complete.
A: Call .Close on the child dialog even if not shown. WPF believes the dialog may still be visible somewhere and is waiting for it to close before allowing the application to close. The window is cleaned up if ShowDialog is called, but not if it isn't called.
A: Use a Span tag to specify the bold part, as in:
<TextBlock >This is the normal part and <Span FontWeight="Bold">this is the bold part</Span>inside the normal font sent.</TextBlock>
A: Bind the Tag attribute of the ItemsControl to this object, then use a RelativeSource-type binding in your DataTemplate control to find the ItemsControl's Tag. For example, assume the following:
1. You have a class named RepositoryInfo with the following fields:
string Name
string ServerUri
2. The ViewModel exposes the following properties:
RepositoryInfo CurrentRepository
BindingList<RepositoryInfo> KnownRepositories
3. You have an ItemsControl bound to KnownRepositories
<ItemsControl ItemsSource="{Binding KnownRepositories}">
To bind a TextBlock in the ItemsControl's DataTemplate to show the name of the current repository, do the following:
1. Add the following tag to the ItemsControl
Tag="{Binding CurrentRepository}"
2. Add the following TextBlock to the DataTemplate
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=ItemsControl,AncestorLevel=1,Mode=FindAncestor}, Path=Tag.Name}" Margin="8 0 8 0">
A: For example, assume the following:
1. You have a class named RepositoryInfo with the following fields:
string Name
string ServerUri
2. The ViewModel has a property RepositoryInfo CurrentRepository and a BindingList<RepositoryInfo> KnownRepositories
To do this in WPF, you must bind the CurrentRepository property to a value on the ItemsControl, use a multibinding to refer to both the current item and the ItemsControl's Tag, write a MultiValue converter to convert the pair to a font weight, and finally bind FontWeight using the multibinding with the MultiValue converter. To do this:
1. Bind the Tag of the ItemsControl to CurrentRepository by adding the following attribute to it:
Tag="{Binding CurrentRepository}"
2. Write an IMultiValueConverter that compares two values and returns FontWeights.Bold if equal, else FontWeights.Normal:
public class ComparisonToFontWeightConverter : IMultiValueConverter
public object Convert( object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture )
// Compare values[0] and values[1]
if (values[0] != values[1])
return System.Windows.FontWeights.Normal;
else
return System.Windows.FontWeights.Bold;
public object[] ConvertBack( object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture )
throw new NotImplementedException();
3. Bind the FontWeight property of the text control to both CurrentRepository and the current item value:
<TextBlock Text="{Binding Name}" Margin="8 0 8 0">
<TextBlock.FontWeight>
<MultiBinding Converter="{StaticResource ResourceKey=ComparisonToFontWeightConverter}">
<Binding Path="{}"></Binding>
<Binding RelativeSource="{RelativeSource AncestorType=ItemsControl,AncestorLevel=1,Mode=FindAncestor}" Path="Tag"></Binding>
</MultiBinding>
</TextBlock.FontWeight>
</TextBlock>
A: Make sure the ContextMenu is defined in the context of the ItemContainer style to bind the menu's DataContext to the current item in the ItemsControl. Then write an on-clicked handler like this:
private void MyDelete_Click( object sender, RoutedEventArgs e )
var senderControl = sender as System.Windows.FrameworkElement;
RepositoryInfo itemRepositoryInfo;
itemRepositoryInfo = senderControl.DataContext as RepositoryInfo;
System.Windows.MessageBox.Show(System.Windows.Application.Current.MainWindow, "You selected "+itemRepositoryInfo.Name);
KnownRepositories.Remove(itemRepositoryInfo);
A: NOTE: This answer is out of date with respect to "How do I do refer to the item that was clicked on in the ContextMenu handler of an ItemsControl?" See this question for guidance on a better answer.
Bind the Tag property of the control to {Binding} to bind it to them item, then reference OriginalSource.Tag member of MouseButtonEventArgs. For example:
<Image Name="RepositoryIcon" Source="{StaticResource DatabaseConnectedIcon}" Tag="{Binding}"/>
With the following handler in the XAML's View:
private void OnRepositoryControlDoubleClick( object sender, MouseButtonEventArgs eventArgs )
Repository.RepositoryInfo clickedRepository = null;
clickedRepository = eventArgs.OriginalSource as RepositoryInfo;
if (clickedRepository != null)
viewModel.LoginToSpecificRepository(clickedRepository);
A: Disable the native debugger. Either go to Tools|Options|Debugging|Just-in-time and uncheck Native or go to Project Options|Build and uncheck Enable unmanaged code debugging. When the native debugger is enabled, WPF swallows the actual exception and generates a generic "XAML creation error" exception, since the error occured while constructing the object, in it's place.
A: Follow these instructions:
1. Set the default visibility to Collapsed.
2. Add a DataGrid.SelectionChanged handler with the following code:
private void OnEntitySelection(object sender, SelectionChangedEventArgs e)
if (e.RemovedItems.Count == 1)
{
if (entityGrid.GetDetailsVisibilityForItem(e.RemovedItems[0]) == System.Windows.Visibility.Visible)
entityGrid.SetDetailsVisibilityForItem(e.RemovedItems[0], System.Windows.Visibility.Collapsed);
}
if (entityGrid.SelectedItem != null)
{
if (entityGrid.GetDetailsVisibilityForItem(entityGrid.SelectedItem) == System.Windows.Visibility.Visible)
entityGrid.SetDetailsVisibilityForItem(entityGrid.SelectedItem, System.Windows.Visibility.Collapsed);
else
entityGrid.SetDetailsVisibilityForItem(entityGrid.SelectedItem, System.Windows.Visibility.Visible);
}
3. Add a button to the row details to hide the details
entityGrid.SetDetailsVisibilityForItem(entityGrid.SelectedItem, System.Windows.Visibility.Collapsed);
A: Move the type outside of the class or write a custom markup extension to get the type. This is a known bug in the Visual Studio 2010 WPF designer. See http://social.msdn.microsoft.com/Forums/en/wpf/thread/12f3e120-e217-4eee-ab49-490b70031806
A: Follow these instructions:
1. Tag each enum value with a System.ComponentModel.Description attribute with the description to show in the GUI.
2. Write a value converter that converts an enum->description and description->enum value. For Convert, cast value to an Enum, then use reflection to get the DescriptionAttribute.
3. Declare the value converter in the XAML Resources section, making it available for use there. For example:
<v:EnumDescriptionConverter x:Key="EnumDescriptionConverter" />
4. Declare a list the enum values in the XAML. This can be dynamiclaly determined by using ObjectDataProvider as shown below. Note that due to a bug in the Visual Studio WPF Designer, the enum type must not be defined within a class, it must be directly within the specified namespace.
<ObjectDataProvider MethodName="GetValues"
ObjectType="{x:Type sys:Enum}"
x:Key="SourceTypeValues">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="vm:SourceType" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
5. Bind the ComboBox's Items source to the enum value list provider created in step 4. This sets the list of items for the ComboBox's list control to the enum values.
<ComboBox ItemsSource="{Binding Source={StaticResource SourceTypeValues}}" ...>
6. Bind the ComboBox's SelectedItem to the DataContext field to bind.
<ComboBox SelectedItem="{Binding DataSourceType}" ...>
7. Finally, provide a DataTemplate using the value converter defined in step 2. This displays each enum using the description attribute and sets SelectedItem to the value selected.
<ComboBox ...>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource EnumDescriptionConverter}}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
A: You are referring to a value converter with incorrect syntax, lacking the enclosing braces. For example, this XAML generates this error:
<Binding Path="Foreground" Converter="StaticResource BrushToRgbConverter"/>
But this is valid
<Binding Path="Foreground" Converter="{StaticResource BrushToRgbConverter}" />
Add need the following braces: ^^^ ^^^
A: This requires two steps. The MSDN examples are incorrect.
1. In the .Resources section for the Window or UserControl, declare an unnamed ResourceDictionary and use the MergedDictionaries directive with the path to the XAML to merge in. The path must specify the assembly name and relative path within the assembly in the following format: /<assemblyName>;component/<assemblyPath>/<XAML filename with extension>.
2. Define all other resources for this window/user control within that ResourceDictionary tag.
For example:
<UserControl.Resources>
<!-- When using MergedDictionaries, locally defined resources must be within the ResourceDictionary tag -->
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Common;component/Themes/Generic.xaml"/>
</ResourceDictionary.MergedDictionaries>
<v:HideOnEmptyConverter x:Key="HideOnEmptyConverter" />
<v:ShowOnEmptyConverter x:Key="ShowOnEmptyConverter" />
...
</ResourceDictionary>
</UserControl.Resources>
Q: When I use the Visual Studio Designer on a XAML file using a custom markup extension, I get an exception like this:
System.Windows.Markup.XamlParseException Cannot add element to ; the property value is null.
A: The custom XAML extension has an uninitialized public property. Most often, this is a collection type that was not initialized in the constructor. Note that autogenerated object/collection properties are initialized to null, not an instance of the specified type.
A: Use the syntax ContainingClass+InnerClass instead. Note that while WPF and Expression Blend support nested classes, the VS2010 earlier visual designers do not as of 2011 May 18, but Microsoft is considering fixing this. See:
http://connect.microsoft.com/VisualStudio/feedback/details/361509/xaml-designer-cannot-handle-typename-with-nested-classes
http://connect.microsoft.com/VisualStudio/feedback/details/605614/xaml-designer-x-static-nexted-type-error-type-ns-class-nestedclass-was-not-found
http://social.msdn.microsoft.com/Forums/en/vswpfdesigner/thread/098c8b12-e85b-49d3-9d0b-672f1d325c6e
A: There are two ways:
1. Implement a public static function in a non-nested class that returns an instance of the nested class. For example:
public class Foo
{
public static MyConverter Converter { get { return new MyConverter(); } }
public class MyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return Double.Parse(value.ToString()) + 50.0d;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
Then refer to it using standard XAML:
<Label Content="{Binding Path=Width, RelativeSource={RelativeSource Self}, Converter={x:Static local:Foo.Converter}}"/>
2. Refer to the class using proper nested class syntax. Use a + character to separate the containing class name from the inner class. Note that this is compatible with XAML, but the Visual Studio 2010 designer does not handle it well. Also, WPF in general has difficulties in areas with nested classes due to it's assumption that the "." separator always separates a class name from a property name in binding syntax.
A: The property bound to must have both a get and set and the binding mode must be specified as Two-Way for this to work. WPF allows each property of a control to have a different default binding mode. The default binding mode for window location properties is one-way, even thought they require a two-way binding to work as intended with a binding.
A: The correct syntax is exactly "/<Assembly name>;component/<xaml filename or path to it>". For example, "/GuiUtil;component/Common.xaml" is the path for a file named Common.xaml in the root of assembly GuiUtil. The prefix "component/" is a reserved prefix that is required for all resources.
A: There are many possible causes. Check the XAML for additional > characters after end tags. This is caused by invalid XAML syntax that the XAML editor did not flag. For example, the following XAML has an extra > on the 4th line after it's close tag and causes this error.
<t:DataGrid Name="MyGrid" ItemsSource="{Binding testData}" AutoGenerateColumns="False" Margin="0,0,161,32">
<t:DataGrid.Columns>
<t:DataGridTextColumn Header="Value" Binding="{Binding Value,Mode=OneWay}" />
</t:DataGrid.Columns> >
</t:DataGrid>
A: Use the SortDescriptions on a CollectionView. WPF provides view sorting, current record support, and filtering via a ICollectionView-based classes. There are two ways to implement this:
1. Use the default view for the collection
WPF automatically creates a view object for every collection it binds to. To access it in code, call the static method CollectionMethod.GetDefaultView() for the collection property that the control is bound to. This default collection cannot be directly accessed in XAML, but you can accomplish the needed effect by using method #2.
2. Create a custom view
To create a custom view in code:
A. Add a ListCollectionView or BindingListCollectionView to the DataContext (ViewModel or model). Pass the collection to be sorted/filtered/etc in the constructor,
B. Bind the control to the new *CollectionView property instead of the old collection property.
To create a custom view in XAML, you must create a CollectionView static resource, bind it to your data, and bind the control to that instead. For example, if the source data is declared in a static resource, this example sorts ListBox items by City, then State by binding it to a
<Window.Resources>
<src:Places x:Key="places"/>
<CollectionViewSource Source="{StaticResource places}" x:Key="cvs">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="CityName"/>
</CollectionViewSource.SortDescriptions>
<CollectionViewSource.GroupDescriptions>
<dat:PropertyGroupDescription PropertyName="State"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Window.Resources>
<ListBox ItemsSource="{Binding Source={StaticResource cvs}}"
DisplayMemberPath="CityName" Name="lb">
<ListBox.GroupStyle>
<x:Static Member="GroupStyle.Default"/>
</ListBox.GroupStyle>
</ListBox>
A: Create a public static method in the GUI window that does the following:
1. Creates a new System.Threading.Thread object
2. Startup method creates the window, shows the window, runs Dispatcher.InvokeShutdown() on Closed, and runs the Dispatcher.
3. Set the Apartment state of the GUI thread to STA
4. Start the thread
An example follows. Note in this case, the GUI thread must save a new GUI object in the scope of the worker thread so the worker can access it. The two threads synchronize on this action via a event object. Also note that the worker cannot call most methods on this object directly or WPF will throw because the object is called from outside it's GUI thread.
public static ConsoleWindow CreateOwnGuiThread()
{
ConsoleWindow newConsoleWindow = null;
System.Threading.AutoResetEvent consoleCreated = new System.Threading.AutoResetEvent(false);
System.Threading.Thread guiThread = new System.Threading.Thread( () =>
{
newConsoleWindow = new ConsoleWindow();
// Stop message pump when window is closed
newConsoleWindow.Closed += (senderB, eventB) => {newConsoleWindow.Dispatcher.InvokeShutdown();};
newConsoleWindow.Show();
// Notify the parent worker that we've initialized
consoleCreated.Set();
// Run message pump
System.Windows.Threading.Dispatcher.Run();
}
);
// GUI threads must run in STA
guiThread.SetApartmentState(System.Threading.ApartmentState.STA);
guiThread.Start();
// Wait for worker GUI thread to initialize
consoleCreated.WaitOne();
return newConsoleWindow;
}
For reference, see http://eprystupa.wordpress.com/2008/07/28/running-wpf-application-with-multiple-ui-threads/.
A: Ask the dispatcher to run a NOP delegate at Background priority. This will cause it to process all pending operations of equal or greater priority first, updating the window. For example:
System.Windows.Threading.DispatcherFrame frame = new System.Windows.Threading.DispatcherFrame();
System.Windows.Threading.Dispatcher.CurrentDispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Background,
new Func<Object, Object>((arg) => {
((System.Windows.Threading.DispatcherFrame)arg).Continue = false;
return null;
}), frame);
System.Windows.Threading.Dispatcher.PushFrame(frame);
A: Convert the text column to a Template column, specify the bound control to display the column for each row, then set the Tooltip member of that control. To use a basic text tooltip, just set Tooltip=. This property is also a content property, so to use a custom tooltip, set the property directly. For example, convert this column definition:
<t:DataGridTextColumn Header="Name" Binding="{Binding Info.Name}" Width="Auto" CanUserSort="True">
To this:
<t:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Info.Name, Mode=OneWay}" ToolTip="{Binding Info.Name}">
</TextBlock>
</DataTemplate>
</t:DataGridTemplateColumn.CellTemplate>
To display a fully custom tooltip window, set the ToolTip property using this syntax:
<TextBlock Text="{Binding Info.Name, Mode=OneWay}">
<TextBlock.ToolTip>
<Border CornerRadius="3" BorderThickness="4" HorizontalAlignment="Left" VerticalAlignment="Top" Width="325" Height="90">
<Grid>
// Neat stuff goes here, DataContext is an element in the DataGrid Items collection
</Grid>
</Border CornerRadius="3" BorderThickness="4">
</TextBlock.ToolTip>
</TextBlock>
In this case, it may be advisable to disable the default shadow by encapsulating the TextBlock.ToolTip children in the following element:
<ToolTip HasDropShadow="False" Background="{x:Null}" BorderBrush="{x:Null}">
</ToolTip>
See http://www.cnblogs.com/sheva/archive/2006/08/24/485790.html.
A: You must make the property a dependency property. To do so:
1. Declare a property identifier. These are typically public because they are readonly and may be used by other code to construct binding expressions, but they do not have to be. The textual name specified for the property in the registration should match the name of the property on the control in step 2.
public static readonly DependencyProperty Property_ReferenceTime = DependencyProperty.Register("referenceTime", typeof(DateTime), typeof(TimerTextBlock), new UIPropertyMetadata(DateTime.Now));
2. Add a public property to the control class. Use GetValue/SetValue to get and set the property value, and call RaisePropertyChanged to notify WPF of changes to the property value:
public DateTime referenceTime
{
get
{
return (DateTime) GetValue(Property_ReferenceTime);
}
set
{
SetValue(Property_ReferenceTime, value);
RaisePropertyChanged("referenceTime");
}
}
A: There are none in NET 3.5. To workaround this, convert the TimeSpan to a DateTime, then use the DateTime format strings. For example:
TimeSpan myTimeSpan
DateTime tsAsDateTime = new DateTime(myTimeSpan.Ticks);
A: Use a DispatchTimer. This will run your method on the GUI thread. It is the WPF direct equivalent of the Win32 SetTimer/WM_TIMER facility. For example, to call UpdateElapsedTime perioidically:
System.Windows.Threading.DispatcherTimer updateTimer;
updateTimer = new System.Windows.Threading.DispatcherTimer(System.Windows.Threading.DispatcherPriority.Background);
updateTimer.Stop();
updateTimer.Tick += new EventHandler( (sourceObject, args) => { UpdateElapsedTime(); });
A: There are two ways, depending on what you need:
1. To default the property to a constant, specify the constant in the property registrations. For example, this property registration sets the default value of a property named referenceTime to DateTime.Now:
public static readonly DependencyProperty Property_ReferenceTime = DependencyProperty.Register("referenceTime", typeof(DateTime), typeof(TimerTextBlock), new UIPropertyMetadata(DateTime.Now));
2. To default the property to a binding expression, run code in the Initialized or Loaded event.
A: Manually create the binding by setting fields in the System.Windows.Data.Binding instead. For example, to create a binding equivalent to {Binding RelativeSource=RelativeSource Mode=Self}, Path=elapsedTimeFormatted, Mode=OneWay}, do the following:
var newBinding = new System.Windows.Data.Binding();
newBinding.RelativeSource = new System.Windows.Data.RelativeSource(System.Windows.Data.RelativeSourceMode.Self);
newBinding.Path = new PropertyPath("elapsedTimeFormatted");
newBinding.Mode = System.Windows.Data.BindingMode.OneWay;
SetBinding(TextProperty, newBinding);
A: Enable WPF's binding logging by setting the trace level for the binding to High like this:
System.Diagnostics.PresentationTraceSources.SetTraceLevel(newBinding, System.Diagnostics.PresentationTraceLevel.High);
SetBinding(TextProperty, newBinding);
A: In the Loaded event.
A: The layout location settings are incorrect. The control is positioned using Margin inside a parent, most likely a grid. To resolve this:
1. Use a Canvas or create rows and columns in the parent grid to position the control absolutely.
2. Set Width and Height on the ellipse to fix it's size. Note that this alone will not resolve the issue.
A: Use the syntax "parent.child". For example, if the DataContext has a property named "address" which has a public property "city", use the binding expression {Binding Path=address.city} to bind to the city property of address. This is supported for multiple parents. HOWEVER, note that if the parent or any component along the path to the child becomes NULL, WPF will NOT refresh the binding when the parent or component receives a valid value. You must force this by manually refreshing the parent or the binding itself. The former method is recommended as it will automatically affect all controls using nested properties from that parent. To do the later, call GetBindingExpression with the DependencyProperty constant identifying the bound property on the control, then call UpdateTarget on this to update the target that receives the value from the binding.
A: You must begin the format string with {} to permit spaces. For example, to display a DateTime as <time> <date> with a space between <time> and <date>, use a binding string like this: Text="{Binding Path=runStartTime, StringFormat={}{0:t} {0:M}}"
A: Set the window's SizeToContent property to "WidthAndHeight".
A: Use the string "{x:Static sys:DateTime.MinValue}". For example, a DataTrigger that fires when a property is equal to DateTime.MinValue looks like this:
<DataTrigger Binding="{Binding Path=programEndTime}" Value="{x:Static sys:DateTime.MinValue}">
...data trigger stuff...
A: Use the x:Static markup extension. For example, to use an enum value for comparison in a DataTrigger, first import the namespace where the enum is defined:
xmlns:AutomationProgramDesignerView="clr-namespace:Cybernet.Vsil.UI.AutomationProgramDesigner.View;assembly=AutomationProgramDesigner"
Then use the following syntax to refer to the enum value Initializing in the ProgramRunState enumeration located in AutomationProgramDesignerView:
<DataTrigger Binding="{Binding Path=currentProgramState}" Value="{x:Static Member=AutomationProgramDesignerView:ProgramRunState.Initializing}">
A: You must use a different syntax to specify the Binding parameters as individual elements instead of packged into a string. For example, say you have a TextBlock that you would like to be invisible (Collapsed) if the property isConnected is true. You have an IValueConverter implementation named BoolToVisibleConverter that converts bool->Visibility as true->Visible and false->collapsed, but in this case you want it to return true->Collapsed and false->Visible. You want to use the same converter and simply change it's behavior via a parameter. Use the following syntax to specify the converter parameter:
Resource declaration (assuming the class BoolToVisibleConverter exists in the commonConverters namespace):
<commonConverters:BoolToVisibleConverter x:Key="BoolToVisibleConverter" />
Window XAML:
<TextBlock>
<TextBlock.Visibility>
<Binding Path="isConnected" Converter="{StaticResource BoolToVisibleConverter}">
<Binding.ConverterParameter>
<sys:Boolean>False</sys:Boolean>
</Binding.ConverterParameter>
</Binding>
</TextBlock.Visibility>
Remote services are currently unavailable.
</TextBlock>
A: Set the Padding property to 0. Labels have a default Padding of 5, which makes them much taller than they need to be.
A: Move the Height property binding so it appears after all of the TabItems. XAML properties are evaluated in the order encountered. If the Height attribute is set before the TabItem definitions, it will never be recalculated because the Items property is not set equal to something else, so no PropertyChanged notification is ever fired. Logically, it does change as items are added to the collection, but this does not fire the notification needed to force recalculate of the Height binding.
A: Add a 32-bit (x86) configuration to this project and do all visual design in that configuration, or use a different designer. The Visual Studio 2010 designer runs as a 32-bit process and cannot load the assemblies produced by a 64-bit project configuration.
A: Unblock the assembly file in Explorer. This typically occurs when downloading an assembly from the Internet. Internet Explorer will mark the file as originating from the Internet Zone, causing Windows to block access to it due to Windows NET assembly security. The steps to unblock the file are:
Locate the assembly file in Explorer
Right click the file and select properties
At the bottom of the General tab, click the Unblock button.
A: You must tell the Visual Studio XAML compiler to ignore these elements by using the OpenXML ignore element. Assuming the Blend namespace providing the DesignHeight/DesignWidth elements is imported as d (xmlns:d="http://schemas.microsoft.com/expression/blend/2008"), add the following to to your window/user control XAML to resolve this:
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
The designer will still recognize and use the d: settings, but the builder will no longer report an error.
A: Set ResizeMode="CanResize" and the Width and Height properties of the window to the initial size it should be, then add a Window Loaded handler that calls ClearValue(WidthProperty) and ClearValue(HeightProperty).
A: Hook the LoadCompleted event before setting Source. If this logic is in an event handler, as is most likely, you must return from the handler for the WebBrowser to handle the load. The following code which seems correct to a Win32 programmer will deadlock in WPF:
webBrowser.LoadCompleted += new LoadCompletedEventHandler((senderObject, args) => loadCompletedEvent.Set()); webBrowser.Source=sourceURI;
A: Disable IE's LOCALMACHINE_LOCKDOWN security feature by calling CoInternetSetFeatureEnabled(INTERNETFEATURELIST.FEATURE_LOCALMACHINE_LOCKDOWN, SET_FEATURE_ON_PROCESS, false) in your constructor. In XPSP2, Microsoft introduced new security features in Internet Explorer that also apply to embedded IE instances. These can be disabled by calling CoInternetSetFeatureEnabled. This corresponds to IE's Allow Active Content setting. This requires a pinvoke call as there is no managed interface. The declarations needed are as follows.
[Flags] private enum CoInternetSetFeatureEnabled_SetFlags { SET_FEATURE_ON_THREAD = 0x00000001, SET_FEATURE_ON_PROCESS = 0x00000002, SET_FEATURE_IN_REGISTRY = 0x00000004, SET_FEATURE_ON_THREAD_LOCALMACHINE = 0x00000008, SET_FEATURE_ON_THREAD_INTRANET = 0x00000010, SET_FEATURE_ON_THREAD_TRUSTED = 0x00000020, SET_FEATURE_ON_THREAD_INTERNET = 0x00000040, SET_FEATURE_ON_THREAD_RESTRICTED = 0x00000080 } private enum INTERNETFEATURELIST { FEATURE_OBJECT_CACHING = 0, FEATURE_ZONE_ELEVATION = 1, FEATURE_MIME_HANDLING = 2, FEATURE_MIME_SNIFFING = 3, FEATURE_WINDOW_RESTRICTIONS = 4, FEATURE_WEBOC_POPUPMANAGEMENT = 5, FEATURE_BEHAVIORS = 6, FEATURE_DISABLE_MK_PROTOCOL = 7, FEATURE_LOCALMACHINE_LOCKDOWN = 8, FEATURE_SECURITYBAND = 9, FEATURE_RESTRICT_ACTIVEXINSTALL = 10, FEATURE_VALIDATE_NAVIGATE_URL = 11, FEATURE_RESTRICT_FILEDOWNLOAD = 12, FEATURE_ADDON_MANAGEMENT = 13, FEATURE_PROTOCOL_LOCKDOWN = 14, FEATURE_HTTP_USERNAME_PASSWORD_DISABLE = 15, FEATURE_SAFE_BINDTOOBJECT = 16, FEATURE_UNC_SAVEDFILECHECK = 17, FEATURE_GET_URL_DOM_FILEPATH_UNENCODED = 18, FEATURE_TABBED_BROWSING = 19, FEATURE_SSLUX = 20, FEATURE_DISABLE_NAVIGATION_SOUNDS = 21, FEATURE_DISABLE_LEGACY_COMPRESSION = 22, FEATURE_FORCE_ADDR_AND_STATUS = 23, FEATURE_XMLHTTP = 24, FEATURE_DISABLE_TELNET_PROTOCOL = 25, FEATURE_FEEDS = 26, FEATURE_BLOCK_INPUT_PROMPTS = 27, FEATURE_ENTRY_COUNT = 28 }; [DllImport("urlmon.dll")] [PreserveSig] [return:MarshalAs(UnmanagedType.Error)] static extern int CoInternetSetFeatureEnabled( INTERNETFEATURELIST FeatureEntry, CoInternetSetFeatureEnabled_SetFlags dwFlags, bool fEnable );
If you need more control such as this, such as to force the zone that the WebBrowser control runs in or get certain security information, you must implement a custom security manager (IInternetSecurityManager), along with IOleClientSite/IActiveScriptSite to install the hook. See http://msdn.microsoft.com/en-us/library/ms537182(v=vs.85) for more information.
A: This is a bug that Microsoft is aware of. There is currently no programmatic workaround. Microsoft suggests you open the site in the full IE browser and select Always Allow at the security prompt. See this msdn blog and this posting acknowledging this as an issue.
A: One way to do this is to reassign the binding. For example:
void ForceRefreshBinding( FrameworkElement targetControl, DependencyProperty propertyToRefresh ) { BindingExpression targetExpression = targetControl.GetBindingExpression(depprop); Binding propertyBinding = targetExpression.ParentBinding; cntrl.SetBinding(targetControl, propertyBinding); }
A: Use commas to separate the values, as in: <ns:SomeControl Flags="FlagA,FlagB" /> Courtesy stackoverflow.
A: No. Identifier generation only works for window/user control children - children of partial classes generated by the designer. To accomplish this, add a RESX file to your project instead and define the strings in it. For more information, see the bottom of this link.
A: Use a trigger, specified via style. However, make sure that the control does NOT specify a value for Content, or the Content will never be changed regardless of the trigger. Instead, set the initial value using a Setter inside the Style block. For example, the following works:
<CheckBox Name="CaseSensitiveSetAll" HorizontalAlignment="Right" Margin="0 0 5 0" Width="80"> <CheckBox.Style> <Style TargetType="{x:Type CheckBox}"> <Setter Property="Content" Value="Select All"/> <Style.Triggers> <Trigger Property="IsChecked" Value="False"> <Setter Property="Content" Value="Select All" /> </Trigger> <Trigger Property="IsChecked" Value="True"> <Setter Property="Content" Value="Unselect All" /> </Trigger> </Style.Triggers> </Style> </CheckBox.Style> </CheckBox>
But if you added a Content="Select All" attribute to the Checkbox element, it would not. Source is this MSDN posting.
A: This is non-obvious because all NET COM objects are descended from System.ComObject. This is the type that WPF searches for properties, but of course it doesn't find any. This solution assumes that the COM objects are all of the same type and that the project has a reference to an interop DLL for this type. To fix this problem:
1. Add a namespace for the Interop DLL to the XAML. For example, for the interop DLL VisionCom whose namespace is also named VisionCom, add the following namespace declaration to the XAML:
xmlns:XamlVisionCom="clr-namespace:VisionCom;assembly=VisionCom"
2. Bind the ComboBox's ItemsSource to the collection of COM objects.
3. Create a DataItemTemplate for the ComboBox.
4. In the DataItemTemplate, bind the control you wish to use using a special XAML syntax where you specify the type to cast the object to, then the property of the type to use. This syntax is (namespace:interface.property), used after the equals sign in the standard Binding Path= statement, as in:
<ComboBox ItemsSource="{Binding Path=updateConfiguration.strategyDataItems}" > <ComboBox.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding Path=(XamlVisionCom:IATIVisionDataItemInterface.FullDataItemName)}"/> </DataTemplate> </ComboBox.ItemTemplate> </ComboBox>
Reference this MSDN posting by a Microsoft employee.
A: Set it via the EditingElementStyle property of the element. Using ElementStyle will not work. For example:
<DataGridComboBoxColumn Header="Data Item" MinWidth="150"> <DataGridComboBoxColumn.EditingElementStyle> <Style TargetType="ComboBox"> <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=updateConfiguration.strategyDataItems}"/> <Setter Property="ToolTipService.ToolTip" Value="The VISION strategy data item whose address will be set equal to the address of the symbol specified to the right" /> <Setter Property="ComboBox.ItemTemplate"> <Setter.Value> <DataTemplate> <TextBlock Text="{Binding Path=(XamlVisionCom:IATIVisionDataItemInterface.FullDataItemName)}"/> </DataTemplate> </Setter.Value> </Setter> </Style> </DataGridComboBoxColumn.EditingElementStyle> </DataGridComboBoxColumn>
A: There are two ways to to do this. To get Windows to drop the drop-shadow according to display settings, the best way to do this, the workaround is to configure the WPF window to be resizeable, but set the Min=Max, so it can't actually be resized. For example:
<Window x:Class="Duo.Gui.AuthenticationWizard"
...
Height="360" Width="625" 360" MinWidth="625" MaxHeight="360" MaxWidth="625"
WindowStyle="None" ResizeMode="CanResize" >
Courtesy this Stackoverflow posting.
The other way to resolve this is to enable AllowTransparency in the parent window and manually draw a drop-shadow. This is not recommended because it will not fit with different OS visual themes, but can accomplish the effect.
A: Do the following:
1. Create a System.Diagnostics.TextWriteListener.
2. Call System.Diagnostics.PresentationTraceSources.Refresh().
3. Attach the listener to each source in System.Diagnostics.PresentationTraceSources and set their Switch.Level to All.
Courtesy this msdn blog link.
A: Add a config file (app.config) to your WCF project and put these settings in it: https://msdn.microsoft.com/en-us/library/ty48b824(v=vs.110).aspx
The global mstest config file may also need some settings added as per: http://blogs.msdn.com/b/aseemb/archive/2013/01/25/how-to-enable-mstest-logs.aspx
A: This is easy but requires a few steps:
1. Create a RESX file if needed, then determine the namespace and name of the resource class. For example, all projects default to a namespace of [DefaultNamespace].Properties with a class of Resources.
2. In the XAML Window element, add a namespace declaration for this namespace. For example:
xmlns:resx="clr-namespace:Duo.Properties"
3. To use a resource string, use an x:Static referencing the named resource within the resource class in this namespace. For example:
<Button ToolTip="{x:Static resx:Resources.Tooltip_Push}" />
A: In Visual Studio, goto the RESX file and change the Access Modifier to Public.