Best wpf questions in April 2012

"Are you sure?" prompts. Part of the ViewModel or purely the view?

20 votes

I've been toying with where to put "are you sure?" type prompts in my MVVM WPF app.

I'm leaning towards thinking that these are purely part of the View. If the ViewModel exposes a DeleteCommand, then I would expect that command to delete immediately.

To integrate such prompts into the ViewModel, it would have to expose a separate RequestDeleteCommand, a DeletePromptItem property for binding the prompt against, and which could also double as a trigger to show the prompt.

Even with this, there's nothing stopping a unit test calling DeleteCommand directly, unless I put specific logic in the ViewModel to require DeletePromptItem to match the item supplied as an argument to DeleteCommand.

However, this all just seems like noise in the ViewModel to me. The prompt is more a user interface issue to guard against misclicks etc. To me this suggests it should be in the view with a confirmed prompt calling the DeleteCommand.

Any thoughts?

The prompts should definitely not be part of the ViewModel, but this doesn't necessarily mean that the best solution is to hardcode them in the View (even though that's a very reasonable first approach).

There are two alternatives that I know of which can reduce coupling between View and ViewModel: using an interaction service, and firing interaction requests. Both are explained very well here; you might want to take a look.

The general idea is that you abstract how asynchronous interactions are done and work with something more similar to event-based logic while at the same time allowing the ViewModel to express that it wants to interact with the user as part of an operation; the net result is that you can document this interaction and unit test it.

Edit: I should add that I have explored using Prism 4 with interaction requests in a prototype project and I was very pleased with the results (with a bit of framework code going you can even specify what's going to happen on a specific interaction request entirely in XAML!). I would love to give some snippets but it will have to wait for tomorrow.

Is there any way to use StaticResource in a WPF control library and be able to view at design-time?

11 votes

I have a WPF Control Library that is being added to a Windows Form Application. We want to allow the controls to be localizable, however I am not sure how to FULLY accomplish this without duplicating code. This is what I am doing now.

Basically, in the Windows Form App, before the main application kicks off, I am instantiating an App.xaml that live within the forms app (containing my links to my resources that also live within the forms app). This works perfectly for runtime.

However, my user controls all have Content="{StaticResource SomeVariableName}", which end up being blank. I can fix this by having an app.xaml and appropriate resource dictionaries in my control library that match those in my windows forms app. However, this is duplicated code.

Things I have already tried to no avail:

  • Instantiate the App.xaml that lives within the user control library from within my forms app. This does not work because the URIs to my resources is looking for an embedded resource, not my local resource dictionary (I could then simply copy the resource files from the control to an appropriate location within my forms app on build). Could I leverage DeferrableContent here? There is not much online as far as I could find on this attribute and how it should be used, though.
  • I would like to use post builds for both App and dictionaries, however, the App instantiation is a static reference to a compiled App.xaml as far as I can tell. So, App.xaml must live within the form at least
    • I did try to have a duplicated App.xaml with a post build moving the resourcedictionary.xaml. I figured that a duplicated app.xaml is ok since that is the driving force and you might not want to rely on one from the control anyway (which circles back and makes you wonder if you should then have the App.xaml in the control at all? Unless you want to allow a default that uses embedded resources....) That too failed saying it could not find the resource even though it was placed where the URI should have been pointing to. The decompiled code points to Uri resourceLocater = new Uri("/WindowsFormsApplication3;component/app.xaml", UriKind.Relative);

So, Is there any way to allow for this to work AND have design time viewing of the component defaults AND avoid duplication? Or, is the duplication OK in this case? If my 2nd bullet's sub-item seems ok (duplicated App.xaml with build copied resourcedictionaries), how do I make it not look for a component level item, but instead a file level one?

Last question (and I can post this separately if necessary) that I just paid attention to. My App.xaml is being built into the code, so that does not allow me to create new ResourceDictionaries on the fly anyway. Is there any way to do this?

Final option...possibly the best one? - I plan on using Andre van Heerwaarde's code anyway, so should I just check for the existence of a file and add it as a merged resource on the fly? Basically, have one App.xaml in my user control that links to a default embedded ResourceDictionary. And, then have the code look for the appropriate localized resources on the fly, which can be relative file paths? The only downside I see here is that the default cannot be changed on the fly...which I could probably even have that look in a specified place (using some sort of convention) and have that preferred over the built-in one?

Oh, and my reason for not wanting embedded resources is so that end users can add/modify new localized resources after the build is deployed.

I can add code if it will help you visualize this better, just let me know.

UPDATE

I am now running into a further problem with styling and not just localizing.

Here is an example of one of the internal buttons on one of the controls:

<Button Style="{StaticResource GrayButton}"

Some more things I tried/thought:

  • I cannot create an app.xaml (that would never be used) with the ResourceDictionary set up as ApplicationDefinitions are not allowed in library projects. I could embed this in the control's resources, but then that would always take precedence over any application level resources and I lose customizability.

Here is a connect case that actually sounds like what I am looking for, however it does not provide any real solution to this

The solution (beyond the top..which does not work) that I can think of that might work (and have yet to try) also seems like a lot of work for something that I would think should be simple. But, I might be able to create some dependency properties in the control that I can Bind to and then allow those to be overriden by the project that will be using the control. As I said, that seems like a lot of work for a pretty simple request :). Would this even work? And more importantly, is there a better, simpler solution that I am missing?

I've run into this problem once, and I resolved it by dropping the whole "Resources are objects indexed by key in canonical dictionaries" thing.

I mean, the simple fact of defining a resource in one project and referencing it in another by it's "key" should give goosebumps to any sane person. I wanted strong references.

My solution to this problem was to create a custom tool that converts my resource xaml files to static classes with a property for each resource:

So MyResources.xaml:

<ResourceDictionary>
  <SolidColorBrush x:Key="LightBrush" ... />
  <SolidColorBrush x:Key="DarkBrush" ... />
</ResourceDictionary>

Becomes MyResources.xaml.cs

public static class MyResources {

  static MyResources() {
    // load the xaml file and assign values to static properties
  }

  public static SolidColorBrush LightBrush { get; set; }
  public static SolidColorBrush DarkBrush { get; set; }

}

For referencing a resource, you can use the x:Static instead of StaticResource:

<Border 
   Fill="{x:Static MyResources.LightBrush}"
   BorderBrush="{x:Static MyResources.DarkBrush}"
   ... />

Now you got strong references, autocompletion and compile time check of resources.

Running a WPF control in another thread

9 votes

I am using a visual control in my project that is from a library that I do not have the source to.
It takes too long to update (200ms, roughly) for good UI responsiveness with three of these controls on-screen at once. (I might need to update all three at once, which leaves my UI stuck for ~600ms while they are all thinking).

I have read some posts about TaskSchedulers, and am beginning to investigate the Parallel task features as a way of running each of these controls in their own thread. The platform will be multi-core, so I want to take advantage of simultaineous processing.

The problem is that I don't even know what I don't know about how to go about this, though..

Is there a suitable design pattern for running a control in a separate thread from the main UI thread in WPF?

Specifically: it is a third party map control, that when given a new location or zoom level takes far too long to redraw (~200ms). With perhaps three of these updating at a maximum of 4Hz - obviously they won't keep up..
I have encapsulated the WPF control in a usercontrol, and need to run each instance in it's own thread, while still capturing user input (mouse clicks, for example).

UPDATE: while I am feeling around for a solution, I have implemented the following so far.
My main (UI) thread spawns a thread that creates a new window that contains the control in question, and locates it in the correct position (so that it looks like it is just a normal control).

_leftTopThread = new Thread(() =>
{
   _topLeftMap = new MapWindow()
   {
      WindowStartupLocation = WindowStartupLocation.Manual,
      Width = leftLocation.Width,
      Height = leftLocation.Height,
      Left = leftLocation.X,
      Top = leftLocation.Y,
      CommandQueue = _leftMapCommandQueue,
   };

   _topLeftMap.Show();
   System.Windows.Threading.Dispatcher.Run();

});

_leftTopThread.SetApartmentState(ApartmentState.STA);
_leftTopThread.IsBackground = true;
_leftTopThread.Name = "LeftTop";
_leftTopThread.Start();

Where CommandQueue is a Thread-safe BlockingCollection Queue for sending commands to the map (moving the location, etc).
The problem is now that I can either

  • have user input due to the System.Windows.Threading.Dispatcher.Run() call
  • or block on the CommandQueue, listening for commands sent by the main thread

I can't spin waiting for commands, because it would soak up all my thread CPU!
Is it possible to block and have the event message-pump working?

Well, I have a method that works - but it may well not be the most elegant..

I have a window that contains my third party (slow-rendering) control in the XAML.

public partial class MapWindow : Window
{
    private ConcurrentQueue<MapCommand> _mapCommandQueue;
    private HwndSource _source;

    // ...

}

My main (UI) thread contructs and starts this window on a thread:

_leftTopThread = new Thread(() =>
{
   _topLeftMap = new MapWindow()
   {
      WindowStartupLocation = WindowStartupLocation.Manual,
      CommandQueue = _leftMapCommendQueue,
   };

    _topLeftMap.Show();
    System.Windows.Threading.Dispatcher.Run();

});

_leftTopThread.SetApartmentState(ApartmentState.STA);
_leftTopThread.IsBackground = true;
_leftTopThread.Name = "LeftTop";
_leftTopThread.Start();

I then get a handle to the window in the thread (after it has initialised):

private IntPtr LeftHandMapWindowHandle
{
    get
    {
        if (_leftHandMapWindowHandle == IntPtr.Zero)
        {
            if (!_topLeftMap.Dispatcher.CheckAccess())
            {
                _leftHandMapWindowHandle = (IntPtr)_topLeftMap.Dispatcher.Invoke(
                  new Func<IntPtr>(() => new WindowInteropHelper(_topLeftMap).Handle)
                );
            }
            else
            {
                _leftHandMapWindowHandle = new WindowInteropHelper(_topLeftMap).Handle;
            }
        }
        return _leftHandMapWindowHandle;
    }
}

.. and after putting a command onto the thread-safe queue that is shared with the threaded window:

var command = new MapCommand(MapCommand.CommandType.AircraftLocation, new object[] {RandomLatLon});
_leftMapCommendQueue.Enqueue(command);

.. I let it know it can check the queue:

PostMessage(LeftHandMapWindowHandle, MapWindow.WmCustomCheckForCommandsInQueue, IntPtr.Zero, IntPtr.Zero);

The window can receive my message because it has hooked into the window messages:

protected override void OnSourceInitialized(EventArgs e)
{
    base.OnSourceInitialized(e);

    _source = PresentationSource.FromVisual(this) as HwndSource;
    if (_source != null) _source.AddHook(WndProc);
}

..which it then can check:

private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) // 
{
    // Handle messages...
    var result = IntPtr.Zero;

    switch (msg)
    {
        case WmCustomCheckForCommandsInQueue:
            CheckForNewTasks();
            break;

    }
    return result;
}

..and then execute on the thread!

private void CheckForNewTasks()
{
    MapCommand newCommand;
    while (_mapCommandQueue.TryDequeue(out newCommand))
    {
        switch (newCommand.Type)
        {
            case MapCommand.CommandType.AircraftLocation:
                SetAircraftLocation((LatLon)newCommand.Arguments[0]);
                break;

            default:
                Console.WriteLine(String.Format("Unknown command '0x{0}'for window", newCommand.Type));
                break;
        }
    }
}

Easy as that.. :)

How to efficiently show graphics in WPF?

7 votes

We have a timeline feature of our software. It shows rows of little blobs which indicate data at different points of time. The code is c#, .Net 4 and WPF. To show a blob, we are currently creating a border (giving it a brush) and adding it to a grid. This grid is then added to a parent grid which forms the rows.

This is fine when the timeline shows relatively small numbers of blobs, but when the data is very busy, rendering gets slow, mem usage goes up, and the UI gets unresponsive. (Not surprisingly).

I know we're not doing this in the best way - my question is what is the best way to display graphics like this in wpf?

EDIT: Thank you for the replies below - I will investigate these options. However each requires a large amount of recoding, and my question here is more simple; Is there some control or effect I can use to replace Border which is a lower resource cost?

For data visualization like this I really like DynamicDataDisplay. The component is currently only being maintained/developed for Silverlight but there is an open source (in link) version for WPF which is really a great library.

The library uses IObservable collections and supports DateTime axis values.

There is a built-in marker graph type (example below).

You can use custom markers, it supports zooming and scrolling, lots of other nice features, etc. It is also very fast, even with quite large sets of data.

Since the datasets are IObservable the chart component responds dynamically to changes in the underlying dataset so your graph is updated any time the data collection is updated.

EDIT

Here is an example :

uses :

using System.ComponentModel;
using Microsoft.Research.DynamicDataDisplay;
using Microsoft.Research.DynamicDataDisplay.Charts;
using Microsoft.Research.DynamicDataDisplay.DataSources;
using Microsoft.Research.DynamicDataDisplay.PointMarkers;

main :

 public Window1()
    {
        InitializeComponent();
        //
        const int N = 100;
        List<double> x = new List<double>();
        List<double> y = new List<double>();

        DateTimeAxis dtAxis = new DateTimeAxis();
        _plotter.HorizontalAxis = dtAxis;

        Random rand = new Random();
        for (int i = 0; i < N; i++)
        {   //generate some random data
            x.Add(dtAxis.ConvertToDouble(DateTime.Now.AddDays(i)));
            y.Add(rand.Next(N));
        }

        EnumerableDataSource<double> gX = new EnumerableDataSource<double>(x);
        EnumerableDataSource<double> gY = new EnumerableDataSource<double>(y);
        _MarkerGraph.DataSource = new CompositeDataSource(gX,gY);

        //no scaling - identity mapping
        gX.XMapping = xx => xx;
        gY.YMapping = yy => yy;

        CirclePointMarker mkr = new CirclePointMarker();
        mkr.Fill = new SolidColorBrush(Colors.Red);
        mkr.Pen = new Pen(new SolidColorBrush(Colors.Black),2.0);
        _MarkerGraph.Marker = mkr;
    }

XAML:

<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d3="clr-namespace:Microsoft.Research.DynamicDataDisplay;assembly=DynamicDataDisplay"
Title="Window1" Height="481" Width="651">
<Grid>
    <d3:ChartPlotter Name="_plotter">
        <d3:MarkerPointsGraph Name="_MarkerGraph"/>
    </d3:ChartPlotter>
</Grid>

Output : Program runs...

The DateTime axis scales beautifully, adjusting ticks for days,months, hours, seconds...whatever is appropriate. Easy as pie!

If you do use this package, I highly recommend downloading the source and adding it as a second project to your solution. The documentation is very poor for D3 and the having the source in your project is helpful to figure out how things work. It also makes it very easy to add/extend things if you need to. Be sure to reference your in-solution project if you do this and not the compiled DLL.

Note also that a lot of the available documentation and online examples are targeted for the maintained Silverlight component and not for the open WPF component. Many of the components are different between these two versions so you have to dig through the WPF component to see what's there. The above example is for the v0.3 WPF component.

ShowDialog in Closing-Event

6 votes

If the user closes the Application a Save-File-Message have to be shown (to be sure that he wants to discard the changes of edited files).

to implement this, i have a menuitem with a command-binding (without key-gesture):

private void Command_Exit(object sender, ExecutedRoutedEventArgs e)
{
    Application.Current.Shutdown();
}

the mainwindow has a closing-event. in this event i check if there unsaved files. if yes, the savedialog has to be opened (to choose, which files have to be saved):

private void Window_Closing(object sender, CancelEventArgs e)
    {
        if (sdl.Count() > 0)
        {
            SaveDialog sd = new SaveDialog();
            IEnumerable<Doc> close = sd.ShowDialog(this);
            if (close == null) 
                e.Cancel = true;
            else
                foreach (Doc document in close)
                    document.Save();
        }

    }

in this ShowDialog-Method (implemented in my SaveDialog-Class) i call

bool? ret = ShowDialog();
if (!ret.HasValue)
     return null;
if (!ret.Value)
     return null;

The problem is:

If i use the Alt+F4-Shortcut to close the Application (default-behaviour of the mainwindow) it works and i get the savedialog if there are unsaved files. but if i close the application by executing the Command_Exit-Method, the Method-Call

bool? ret = ShowDialog(); 

returns null and the dialog does not appear.

If i assign the Alt+F4 KeyGesture to the CommandBinding, the problem is switched: Executing Command_Exit works well but Alt+F4 Shortcut not.

What is the reason that the ShowDialog()-Method works not in both cases and how to fix it?

The Application.Current.Shutdown route allows you to listen for the shutdown request by handling the Exit event as detailed here:

http://msdn.microsoft.com/en-us/library/ms597013.aspx

It doesn't detail how it closes windows, so I wouldn't necessarily be convinced that the closing event handler would fire before it closes the application.

The other very standard way to shut the application down is to close the main window (the one shown at the very beginning). This would likely be the Window.Close method, if you are in the context of the window already, just call Close(). This will then hit the closing event handler.

Show live screens of other applications in one application window

Asked on Tue, 03 Apr 2012 by KMC c# wpf
5 votes

Is it possible to show in one application window (maximized) live screens of another applications that are running concurrently.

I have the following conceptual idea (see below screenshot): the main application is showing while multiple excel applications are running concurrently. Instead of clicking (or tabbing) between applications or resize these windows to be shown on screen, I would want to simply have the main application maximized to show life screens of all these opened excel workbooks.

enter image description here

I use periodic calls to PrintWindow for that.

I'm not completely happy with this solution for it seems a bit hacky. But it also scans hidden windows.

The code is

[DllImport("User32.dll")]
public static extern bool PrintWindow(IntPtr hWnd, IntPtr hdcBlt, int nFlags

[StructLayout(LayoutKind.Sequential)]
struct RECT
{
    public int Left;
    public int Top;
    public int Right;
    public int Bottom;
}

public static Bitmap GetWindow(IntPtr hWnd)
{
    RECT rect;
    GetWindowRect(hWnd, out rect);

    int width = rect.Right - rect.Left;
    int height = rect.Bottom - rect.Top;
    if (width > 0 && height > 0)
    {
        // Build device context (dc)
        Bitmap bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
        Graphics gfxBmp = Graphics.FromImage(bmp);
        IntPtr hdcBitmap = gfxBmp.GetHdc();

        // drawing options
        int nFlags = 0;

        // execute call
        PrintWindow(hWnd, hdcBitmap, nFlags);

        // some clean-up
        gfxBmp.ReleaseHdc(hdcBitmap);
        gfxBmp.Dispose();

        return bmp;
    }
    else
    {
        return null;
    }

} // end function getWindow

Passing application state between viewmodels in MVVM WPF application

5 votes

I need to write a small application to read a configuration file and generate some report with it. I was hoping to finally use MVVM but it's quite tricky to get started. Oh, I'm using Caliburn.Micro framework.

So this is what I have, a shell (primary view that hosts other views) that has a ribbon with 3 buttons on it:

1) Open file 2) Show settings 3) Show results

And two other views, SettingsView and ResultsView with buttons to generate and delete a report.

So I guess the view structure would be like this:

ShellView
   Ribbon
      OpenFileButton
      SettingsButton
      ResultsButton
   ContentControl (hosts SettingsView and ResultsView)

SettingsView
    CalculateResultsButton

ResultsView
    CancelResultsButton

The tricky part is this:

1. "Show settings" button is disabled until a file is opened (via Open file). 
2. "Show results" button is disabled until a report is calculated (via a 
    method in SettingsViewModel).
3. If a report is calculated, the CalculateResultsButton is disabled and
   CancelResultsButton is enabled and vice versa.

Please advise how could I achieve this ? I've no ideas what strategy should I go for. My non-MVVM-thinking-brain says that I should create a status variable and then somehow bind those buttons to that variable, but I guess that wont work in a MVVM world, right ? Any code example would be very very very appreciated!

Many thanks!

Since you're using CM you won't need any code-behind. You can delete the .xaml.cs files if you want.

This is a pretty basic example but it should give you an idea on how to control the state of the buttons. In this example, Open will be enabled and the other two are disabled. If you click on Open, Settings is enabled. The same happens with Results once Settings is clicked.

If you need a way to do global state the same concept can be applied by injecting a singleton, SharedViewModel, into the ViewModels and the CanXXX methods can check values in SharedViewModel. This is a SL demo of different things but one is injecting a singleton to share data, the same idea applies in wpf.

ShellView:

<Window x:Class="CMWPFGuardSample.ShellView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Grid Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <StackPanel Grid.Row="0"
                    Orientation="Horizontal">
            <Button x:Name="Open"
                    Content="Open" />
            <Button x:Name="Settings"
                    Content="Settings" />
            <Button x:Name="Results"
                    Content="Results" />
        </StackPanel>
    </Grid>

</Window>

ShellViewModel:

 [Export(typeof (IShell))]
    public class ShellViewModel : PropertyChangedBase, IShell
    {
        private bool _isOpen;
        public bool IsOpen
        {
            get { return _isOpen; }
            set
            {
                _isOpen = value;
                NotifyOfPropertyChange(() => IsOpen);
                NotifyOfPropertyChange(() => CanSettings);
            }
        }

        private bool _isSettings;
        public bool IsSettings
        {
            get { return _isSettings; }
            set
            {
                _isSettings = value;
                NotifyOfPropertyChange(() => IsSettings);
                NotifyOfPropertyChange(() => CanResults);
            }
        }

        public bool IsResults { get; set; }

        public void Open()
        {
            IsOpen = true;
        }

        public bool CanSettings
        {
            get { return IsOpen; }
        }

        public void Settings()
        {
            IsSettings = true;
        }

        public bool CanResults
        {
            get { return IsSettings; }
        }

        public void Results()
        {
        }
    }

Blurry text in WPF even with ClearTypeHinting enabled?

5 votes

I have a grid with this template and styles in WPF/XAML:

<Setter Property="TextOptions.TextFormattingMode" Value="Display" />
<Setter Property="RenderOptions.ClearTypeHint" Value="Enabled" />
<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="{x:Type DataGridCell}">
            <Border Padding="{TemplateBinding Padding}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
                <ContentPresenter x:Name="CellContent" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" RenderOptions.ClearTypeHint="Enabled" />
            </Border>
            <ControlTemplate.Triggers>
                <Trigger Property="IsSelected" Value="True">
                    <Setter TargetName="CellContent" Property="TextOptions.TextFormattingMode" Value="Display" />
                    <Setter TargetName="CellContent" Property="RenderOptions.ClearTypeHint" Value="Enabled" />
                    <Setter TargetName="CellContent" Property="Effect">
                        <Setter.Value>
                            <DropShadowEffect ShadowDepth="2" BlurRadius="2" Color="Black" RenderingBias="Quality" />
                        </Setter.Value>
                    </Setter>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </Setter.Value>
</Setter>

The DropShadowEffect I have when you select a grid row, seems to make the text rendering blurry (gray anti-aliasing):

enter image description here

When I remove the drop shadow effect, it looks clear because it now uses ClearType and not gray sub-pixel anti-aliasing:

enter image description here

I have tried applying RenderOptions.ClearTypeHint="Enabled" to the ContentPresenter as seen above, but it does not help.

How do I force WPF to render the text that gets displayed with drop shadow effect to retain Cleartype anti-aliasing, instead of that ugly blurry gray sub-pixel anti-aliasing?

Some believe it's blurry because of the drop shadow -- this is not true. It's blurry only because ClearType is not used. This is how it looks like in Firefox when shadow AND ClearType:

enter image description here

ClearType enabled text is colorful -- but that blurry text is not, because it does not use ClearType -- it uses gray sub-pixel anti-aliasing and that's not how ClearType works: http://en.wikipedia.org/wiki/ClearType

The question is: how do I enable ClearType for this text?

The DropShadowEffect object cannot work with ClearType. This is stated on the MSDN page How to: Create Text with a Shadow:

These shadow effects do not go through the Windows Presentation Foundation (WPF) text rendering pipeline. As a result, ClearType is disabled when using these effects.

After all, DropShadowEffect is a bitmap effect, not a text effect.

Very simple WPF program locks up (hangs) on keyboard layout change

5 votes

The following program locks up reproducibly whenever the user changes the keyboard layout via a key combination. It does not lock up if the keyboard layout is changed via the tray applet. It does not lock up when changing the layout to English. It does not lock up if the Task never executes.

XAML:

<StackPanel>
    <TextBox></TextBox>
    <Button Click="Button_Click">Click me</Button>
</StackPanel>

C#:

private void Button_Click(object sender, RoutedEventArgs e)
{
    Task.Factory.StartNew(() =>
    {
        var visual = new DrawingVisual();
        using (var context = visual.RenderOpen())
        {
        }
    });
}

Before the button click, I can switch keyboard layouts as I please. After the click the program locks up on the first attempt to switch layouts.

Importantly, this bug only occurs if the layouts are switched via Alt+Shift+2 or Ctrl+Shift+2 (and 3, but not 1).

It’s way, way too late to avoid the use of DrawingVisual on background threads. This has become an integral, core feature of the product. Any ideas for how to work around this are very welcome.

This bug reproduces on .NET 4.0, Win7 32-bit and 64-bit.

Official Microsoft answer:

This issue will no[t] be addressed in the next release of WPF. -WPF Team.

I’m guessing they’re all too busy with WinRT and WPF is on the back burner.

Error template is displayed above other controls, when it should be hidden

5 votes

I'm trying to implement validation in my WPF application using the IDataErrorInfo interface, and I've encountered a not-so-desirable situation.

I have this template which is used when a control fails to validate

<ControlTemplate x:Key="errorTemplate">
    <DockPanel LastChildFill="true">
        <Border Background="Red" DockPanel.Dock="Right" Margin="5,0,0,0" Width="20" Height="20" CornerRadius="10"
                                    ToolTip="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}">
            <TextBlock Text="!" VerticalAlignment="Center" HorizontalAlignment="Center" FontWeight="Bold" Foreground="White" />
        </Border>
        <AdornedElementPlaceholder Name="customAdorner" VerticalAlignment="Center" >
            <Border BorderBrush="red" BorderThickness="1" />
        </AdornedElementPlaceholder>
    </DockPanel>
</ControlTemplate>

Everything is well until I try to display something above the control that failed validation, such as displaying a dock item above it:

Normal display Display when part of the control is hidden

How can I avoid this and make my error template displayed below the dock item, as it should?

EDIT

I found that I could wrap my TextBox with an AdornerDecorator to fix this, but I really don't want to do this for each and every TextBox control in my application. Is there maybe a way to set it with a Style or some other way?

EDIT 2

I could probably change the default TextBox ControlTemplate to include an AdornerDecorator, but I'm not too keen on changing any of WPF's default control templates. Any other suggestions are welcome.

OK, I found a relatively simple solution which doesn't force me to change any control templates.

Instead of decorating each TextBox with an AdornerDecorator like this

<StackPanel>
    <AdornerDecorator>
        <TextBox Text={Binding ...} />
    </AdornerDecorator>
    <AdornerDecorator>
        <TextBox Text={Binding ...} />
    </AdornerDecorator>
</StackPanel>

I can have the AdornerDecorator wrap my entire view, which achieves the same result.

<AdornerDecorator>
    <StackPanel>
        <TextBox Text={Binding ...} />
        <TextBox Text={Binding ...} />
    </StackPanel>
</AdornerDecorator>

This way I can define it at most one time per view.

Lenses for MVC framework in Haskell

5 votes

I've been mulling around the idea of how you'd construct a MVC framework in Haskell in the mold of WPF or AngularJS, but can't seem to find the key types or idea to get started. So unfortunately vague question - has anyone else out there been thinking about this problem?

I see edit-lenses, multi-plate and Compos, but I think they all solve slightly different problems.

My rough sketch of how that would work would be:

  1. Create a model as a plain haskell data structure
  2. Create a set of 'lenses' or commands to modify your model.
  3. Write a HTML (or whatever) template which is parametised by the types in the model.

.

data Model = Page { _title :: String, _content :: [(Int, String)] }

title :: Lens Model String
content :: Int -> Lens Model (Maybe String)

Then I would want to be able to write a function:

Model -> Template Model -> Html

and a function to update parts of my view when I apply a lens.

Lens Model a -> a -> HtmlTemplate Model -> [(Path, Html)]

So I guess the question is - what type would a lens take which can operate on one data structure, then be used to describe the change in another.

One possibility seems to be to create a GADT which wraps all the lenses and then template the HTML over the GADT type which can then be used to match against the template at each step. e.g.

data Lenses a b where
    Title :: Lens Model String -> Lenses Model String
    Item  :: Lens Model String -> Lenses Model (Maybe String)

Then a Html Template data type e.g.

data HtmlTemplate a = Text String 
              | Element String [Attrib a] 
              | forall b. Binding (Lenses a b) (Html b)

To which the Binding element can be pattern matched against directly.

But that seems almost defeating the point, because the model is then joined at the hip to the view.

I wonder has anyone (smarter than I) out there put thought into how this might work? Or even if this is a good idea?

I've been building a large commercial application using lens-based "MVC" in Haskell.

  • Purely functional data structures
  • Lenses for setting and getting (and keeping the data consistent)
  • A DSL for generating a view (template) tied to each lens.

This has been a great experience, and I definitely recommend the approach for detailed structure editing of complex structures.

The approach forces you to

  • Not hack, but use lenses as safe interfaces to your internal model
  • Strong separation of the model -> view
  • Type checking for everything -- lens types to generate view code

There's lots of ways you can design it, but I think it is a very sound design approach. You will want good DSL support for the GUI part.

How to implement commands to use ancestor methods in WPF?

4 votes

I have this context menu resource:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <ContextMenu x:Key="FooContextMenu">
        <ContextMenu.CommandBindings>
            <CommandBinding Command="Help" Executed="{Binding ElementName=MainTabs, Path=HelpExecuted}" />
        </ContextMenu.CommandBindings>

        <MenuItem Command="Help">
            <MenuItem.Icon>
                <Image Source="../Resources/Icons/Help.png" Stretch="None" />
            </MenuItem.Icon>
        </MenuItem>
    </ContextMenu>
</ResourceDictionary>

I want to re-use it in two places. Firstly I'm trying to put it in a DataGrid:

<DataGrid ContextMenu="{DynamicResource FooContextMenu}">...

The ContextMenu itself works fine, but with the Executed="..." I have right now breaks the application and throws:

A first chance exception of type 'System.InvalidCastException' occurred in PresentationFramework.dll

Additional information: Unable to cast object of type 'System.Reflection.RuntimeEventInfo' to type 'System.Reflection.MethodInfo'.

If I remove the entire Executed="..." definition, then the code works (and the command does nothing/grayed out). The exception is thrown as soon as I right click the grid/open the context menu.

The DataGrid is placed under a few elements, but eventually they all are below a TabControl (called MainTabs) which has ItemsSource set to a collection of FooViewModels, and in that FooViewModel I have a method HelpExecuted which I want to be called.

Let's visualize:

  • TabControl (ItemsSource=ObservableCollection<FooViewModel>, x:Name=MainTabs)
    • Grid
      • More UI
        • DataGrid (with context menu set)

Why am I getting this error and how can I make the context menu command to "target" the FooViewModel's HelpExecuted method?

Unfortunately you cannot bind Executed for a ContextMenu as it is an event. An additional problem is that the ContextMenu does not exist in the VisualTree the rest of your application exists. There are solutions for both of this problems.

First of all you can use the Tag property of the parent control of the ContextMenu to pass-through the DataContext of your application. Then you can use an DelegateCommand for your CommandBinding and there you go. Here's a small sample showing View, ViewModel and the DelegateCommand implementation you would have to add to you project.

DelegateCommand.cs

public class DelegateCommand : ICommand
{
    private readonly Action<object> execute;
    private readonly Predicate<object> canExecute;

    public DelegateCommand(Action<object> execute)
        : this(execute, null)
    { }

    public DelegateCommand(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");

        this.execute = execute;
        this.canExecute = canExecute;
    }

    #region ICommand Members

    [DebuggerStepThrough]
    public bool CanExecute(object parameter)
    {
        return canExecute == null ? true : canExecute(parameter);
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Execute(object parameter)
    {
        execute(parameter);
    }

    #endregion
}

MainWindowView.xaml

<Window x:Class="Application.MainWindowView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindowView" Height="300" Width="300"
        x:Name="MainWindow">
    <Window.Resources>
        <ResourceDictionary>
            <ContextMenu x:Key="FooContextMenu">
                <MenuItem Header="Help" Command="{Binding PlacementTarget.Tag.HelpExecuted, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
            </ContextMenu>
        </ResourceDictionary>
    </Window.Resources>
    <Grid>
        <TabControl ItemsSource="{Binding FooViewModels}" x:Name="MainTabs">
            <TabControl.ContentTemplate>
                <DataTemplate>
                    <DataGrid ContextMenu="{DynamicResource FooContextMenu}" Tag="{Binding}" />
                </DataTemplate>
            </TabControl.ContentTemplate>
        </TabControl>
    </Grid>
</Window>

MainWindowView.xaml.cs

public partial class MainWindowView : Window
{
    public MainWindowView()
    {
        InitializeComponent();
        DataContext = new MainWindowViewModel();
    }
}

MainWindowViewModel.cs

public class MainWindowViewModel
{
    public ObservableCollection<FooViewModel> FooViewModels { get; set; }

    public MainWindowViewModel()
    {
        FooViewModels = new ObservableCollection<FooViewModel>();
    }
}

FooViewModel.cs

public class FooViewModel
{
    public ICommand HelpExecuted { get; set; }

    public FooViewModel()
    {
        HelpExecuted = new DelegateCommand(ShowHelp);
    }

    private void ShowHelp(object obj)
    {
        // Yay!
    }
}