wpf discussions.. 090403

You know the drill.. raw, unedited, yet deep and useful WPF conversations !!


Subject: Changing Resources from Triggers

I have a complex ControlTemplate that I want to change colors when the mouse is over it.  The colors are used at various places deep within the template, and some are even in nested templates …. …

Answer:
To change Resources on a Trigger is to change a non-DP property on a Trigger. WPF does not currently support this. As a workaround could you try the following pattern?

 <ControlTemplate>
  <SomeElement1 x:Name="element1">
    <SomeElement1.Style>
      <Style>
        <Style.Resources>
          <SomeResource1 x:Key="blah" />
        </Style.Resources>
      </Style>
    </SomeElement1.Style>
    <SomeElement1.Template>
      <ControlTemplate>
        <SomeElement1_1 SomeProperty="{DynamicResource blah}" />
      </ControlTemplate>
    </SomeElement1.Template>
  </SomeElement1>
  <ControlTemplate.Triggers>
    <Trigger Property="AnotherProperty" Value="anotherValue">
      <Setter Property="Style" TargetName="element1">
        <Setter.Value>
          <Style>
            <Style.Resources>
              <SomeResource2 x:Key="blah" />
            </Style.Resources>
          </Style>
        </Setter.Value>
      </Setter>
    </Trigger>
  </ControlTemplate.Triggers>
</ControlTemplate>
 

Subject: Creating WPF window prevents application from closing

Window window = new Window();

Putting this line anywhere in my WPF application without actually using this window variable prevents my application from closing when I hit the main window close button. Why would creating an instance of Window have this effect? Only if I add a subsequent window.Close() call does my application shut down correctly.

Window window = new Window();

window.Close();

Answer:
If you do Application.Current.Shutdown() your app should close.

I assume you’re doing Application.Current.MainWindow.Close(). There’s a property on Application called ShutdownMode. The default is OnLastWindowClose. Since you’ve created a window and not closed it, your app will never shut down. You can change Application.ShutdownMode to OnMainWindowClose, and you should be fine.


Subject: Coerced value not reflected in control or others bound to it as sources

I have the following xaml. The CustomTextBox overrides metadata for the Text Dependency Property, which calls a coerce method, which upshifts whatever the user enters. However, the upshifted value does not show up in either TextBox. If I move the binding to the 2nd text box, so it binds to the first, it will display the upshifted text correctly. Why is the upshifted string not showing up in the original case (i.e. as below)?

<StackPanel Margin="20" VerticalAlignment="Center">

<Label Content="Target TextBox (with coercion to uppercase)"/>

<src:CustomTextBox x:Name="TargetTextBox"

Text="{Binding ElementName=SourceTextBox,

       Path=Text, Mode=TwoWay,

       UpdateSourceTrigger=PropertyChanged}"

Margin="0,0,0,20"/>

<Label Content="Source TextBox"/>

<TextBox x:Name="SourceTextBox" IsReadOnly="True" Background="LightGray"

Margin="0,0,0,20"/>

</StackPanel>

Answer:
Here’s a bit of background on coercion. The classic case of coercion is the Slider control where the Value property’s value needs to always lie between the MaxValue and the MinValue. So in this regard we envisioned Coersion to be a view concept. Hence we made a design decision not to propagate coerced values through data Binding. Thus the fact that you don’t see a coerced value on CustomTextBox.Text propagate through the Binding back to the source is ‘By Design’. Yes it can be argued that when Binding is used in the way you’ve shown below to bind two UI pieces then one would want to propagate the coerced value through the Binding. Sam Bent (our Data Services guru), has some thoughts on building some configuration parameters on Binding to allow this. However none of that exists in the platform as of today. As for a Binding on a regular TextBox.Text property displaying the upshifted Text, the reason is that the value at the source is transferred as is to the target of a Binding. The special rule about coercion only comes into play when the value at the target is being coerced. 


Subject: Creating Bindings in a Data Template

I’m trying to create a DataTemplate where some non-FE objects bind to the DataContext of the DataTemplate.  My XAML looks something like this?

 <DataTemplate DataType="{x:Type api:SeahorseItem}">
      <Button CommandParameter="{Binding RelativeSource={RelativeSource Self}}">
        <con:DoubleClickButton.Command>
          <con:MetaCommand CommandParameter="{Binding}">
            <con:MetaCommandEntry Command="FocusCommand" CommandParameter="{Binding }" />
            <con:MetaCommandEntry Command="OpenCommand" CommandParameter="{Binding }" />
            <con:MetaCommandEntry Command="OpenInBackgroundCommand" CommandParameter="{Binding }" />
          </con:MetaCommand>
        </con:DoubleClickButton.Command>
      </Button >
    </DataTemplate>

When I run my application I get the following error message:

System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:(no path); DataItem=null; target element is 'MetaCommandEntry' (HashCode=51095287); target property is 'CommandParameter' (type 'Object')

When I actually debug this, the CommandParameters on my entries and the command itself are null.  I’ve done some digging, and it seems that my problem is that my objects are not FEs, and as a result not part of the inheritance tree.  I also saw a neat trick that allows me to make my objects a part of the inheritance tree by making them freezables.  This worked for the MetaCommand, allowing it’s binding to work. But the Entries still evaluate to null. 

Answer:

Could you make the collection property that holds on to the MetaCommandEntries be of type FreezableCollection<MetaCommandEntry> and MetaCommandEntry should also subclass Freezable. The reason for these changes is that InheritanceContext is internal to the framework and Freezable and FreezableCollection are the only two non-FE/FCE public classes that support it.


Subject: DataGrid different template for new row problem.

I’m trying to show a different template for the last row of my DataGrid to show not the default row template but show a line of text say “Click here to add new item”.

I came across this blog https://blogs.msdn.com/vinsibal/archive/2008/11/05/wpf-datagrid-new-item-template-sample.aspx

I improved it a little bit by listening to InitializingNewItem event and saved the Dispatcher trick. But I still need to listen to several event, use VisualTreeHelper to set the focus on the first cell of last row. I wonder if there is a easier way to do this in general. I believe this is a very common scenario.

Answer:

We hear you. We will look to make this scenario easier in a future release. But what you see in the blog is what we have today.


Subject: Font change events?

I need to detect when font setting for a specific element in my FlowDocument changes, either because it’s (local) font property or its container’s property (inheritable) changes. Is it possible? (I do not see an event that looks that way; I need to change some other properties because of the font change). Alternatively, is there any way for me to detect that the document is about to re-render and do these mods then?

Answer:
You could try DependecyPropertyDescriptor.AddValueChanged. The dependency property would be TextElement.FontSizeProperty


Subject: How to display 1st underscore in Label ?

I would like to display 1st underscore “_” in Label. I know 1st “_” means keyboard shortcut. But he don’t use shortcut but want to display it. How to escape make “_” shortcut ?

Obvious Answer:

Try double “_” as markup below.

<Label Content="__Label"/>

Follow-up:

Yes, I did, but I have to add extra underscore to all underscore such as A__B__C__D instead of A__B_C_D.

Next answer:

The simplest solution would be to use TextBlock instead of Label. Otherwise, you could re-template Label to change RecognizesAccessKey to false :

     <ControlTemplate TargetType="{x:Type Label}">
      <Border ...>
        <ContentPresenter ... RecognizesAccessKey="False" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
      </Border>
      ..
    </ControlTemplate>

Subject: Is there any easy way to get the size of a ImageSource

I'm implementing a cache for ImageSource. I was looking the documentation but I could not find a easy way to get the Size (in bytes) of a ImageSource. Is there a easy way to do that?

Answer:

A size property doesn’t make sense for all implementers of ImageSource. The two platform ones (according to MSDN) are DrawingImage and BitmapSource. DrawingImage is specified in XAML, so its size would not be representative of a pixel width x height x depth measure in bytes.

Take a look at the ImageSource documentation and inheritance tree:

https://msdn.microsoft.com/en-us/library/system.windows.media.imagesource.aspx

You can get a size for the pixels of a BitmapSource using PixelWidth, PixelHeight, and Format.BitsPerPixel. Obviously the object itself can store some more information depending on the implementation. So I think you might want to implement a cache for the BitmapSource class rather than ImageSource


Subject: Closest to immediate-mode rendering in WPF

What is the closest I can get to immediate-mode rendering in WPF? Right now I’m overriding OnRender and basically re-populating the DrawingContext on every frame (since a physics engine is involved, everything moves). Is that the best way?

Also, I noticed that there is no way to apply pixel shaders in the DrawingContext like we can do in XNA. Is there any (potentially hacky) way to push a pixel shader into DrawingContext? Seems odd that we can push bitmap effects but not hardware accelerated effects.

Answer:

That’s as close as it gets. Not sure if it matters to you, since you’re changing everything every frame, but it’s probably worth noting that the dirty region logic operates at the Visual level. Which is to say if you draw everything in 1 DrawingContext, you get no dirty subregion support for all that content.

Having said that, what exactly is changing in your scene? If things are moving/rotating while maintaining a rigid shape, it might make more sense to draw everything once, then simply update the transforms every frame with the physics engine inputs. This is much more “WPFy”, and if it fits within the constraints of your system, it should also be more efficient than changing the DC content every frame.

No way to push an effect in a DC. The method of drawing you’re using is not really the one for which WPF is optimized.

Bitmap effects are going away. If you pick up a 4.0 beta build, they’re already gone.


Subject: Making one color in a bitmap transparent

I’m fairly new at WPF, so if there is an obvious answer to this question, it’s likely the right one.

I’m trying to convert some old WinForms code to WPF and I’m running into a snag displaying Bitmap images.  All of the bitmaps in my application have the same background color which is intended to be displayed as transparent.  In WinForms I could achieve this effect by creating an ImageList and setting the TransparentColor property to be this particular color. 

How can I achieve the same effect with WPF?

Answers:

There's no default support in wpf to do this. However Dwayne has blogged about how to do this.https://blogs.msdn.com/dwayneneed/archive/2008/06/20/implementing-a-custom-bitmapsource.aspx

If you have a small number of bitmaps, it’s probably easier to make them transparent yourself in a photo editing app and save as PNG.