Posts Tagged ‘ WPF ’

WPF Bind value to Binding ConverterParameter

Sometimes it would be necessary if we could just bind a value to a ConverterParameter.
For example if you need two properties in the IValueConverter. It is possible to add a ConverterParameter but we cannot bind to it.

<!-- The Converter in the Resources -->
<my:MyConverter x:Key="myConverter" />

<!-- This does not work because we can not bind DEF to the ConverterParameter -->
<TextBlock Text="{Binding Path=ABC, Converter={StaticResource myConverter},ConverterParameter={Binding Path=DEF}}" />

<!-- This solution with the MultiValueConverter works -->
<TextBlock>
  <TextBlock.Text>
    <MutliBinding Converter="{StaticResource myConverter}">
      <MultiBinding.Bindings>
        <Binding Path="ABC" />
        <Binding Path="DEF" />
      </MultiBinding.Bindings>
    </MultiBinding>
  </TextBlock.Text>
</TextBlock>

The MultiValueConverter should look like this

public class MyConverter: IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return (double)values[0] + " " + (double)values[1];
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotSupportedException("Not implemented");
    }
}

The MultiValueConverter is a very powerful feature of WPF which allows us to bind more than one object.

Advertisements

MVVM – Environment – MGDispatchingWorker

In the MVVM pattern I always need the same base structure of the DispatchingWorker.
This class is located between the ViewModel and the Worker. It is responsible for running the actions in the right thread.

And this class has always the same base structure. So I decided to create my own base class which I can easily extend.

Well here is the result. It just contains a few necessary methods to run actions in the GUI-Thread or in a new Worker Thread.

    /// <summary>
    /// This class can be used as a base for the DispatchingWorker of the MVVM Pattern
    /// It contains a few util methods which help to run methods in Threads or to do Actions in the GUI-Thread
    /// </summary>
    public class MGDispatchingWorker
    {
        public DispatchingWorker()
        {
            _currentDispatcher = Dispatcher.CurrentDispatcher;
        }

        #region Field

        private readonly Dispatcher _currentDispatcher;

        #endregion

        #region UtilMethods

        /// <summary>
        /// This method runs the given action in a new thread (not GUI-Thread)
        /// </summary>
        /// <param name="action">The action which should be run in a new Thread</param>
        protected void DoThreadedAction(Action action)
        {
            var thread = new Thread(action.Invoke);
            thread.Start();
        }

        /// <summary>
        /// This method executes the given action in the GUI-Thread
        /// </summary>
        /// <param name="action">The action which should be executed in the GUI-Thread</param>
        protected void DoDispatchedAction(Action action)
        {
            if (_currentDispatcher.CheckAccess())
                action.Invoke();
            else
                _currentDispatcher.Invoke(action);
        }

        /// <summary>
        /// This method executed the given action asynchronous in the GUI-Thread
        /// </summary>
        /// <param name="action">The action which should be executed asynchronous in the GUI-Thread</param>
        protected void DoDispatchedActionAsync(Action action)
        {
            if (_currentDispatcher.CheckAccess())
                action.Invoke();
            else
                _currentDispatcher.BeginInvoke(action);
        }

        #endregion
    }

MVVM – Environment – MGViewModel

In the MVVM pattern I always need the same base structure of the ViewModel.

So I decided to write my own class which could be extended when creating a new ViewModel.
Such that I do not have to implement the same features each time.

This base class implements INotifyPropertyChanged and a few methods which makes it easy to fire this eventt when one of the properties changed.

The NotifyPropertyChanged-Method which takes the propertyExpression parameter is by Eric De Caroufel

public  class MGViewModel : INotifyPropertyChanged
    {
        #region INotifyPropertyChanged Member

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        #region Util Methods

        /// <summary>
        /// This method fires the PropertyChanged-Event
        /// </summary>
        /// <param name="propertyExpression">The expression which contains the variable which was changed</param>
        protected void NotifyPropertyChanged(Expression<Func<object>> propertyExpression)
        {
            var propertyChanged = PropertyChanged;
            if (propertyChanged != null)
            {
                // Retreive lambda body
                var body = propertyExpression.Body as MemberExpression;
                if (body == null)
                    throw new ArgumentException("'propertyExpression' should be a member expression");

                // Extract the right part (after "=>")
                var vmExpression = body.Expression as ConstantExpression;
                if (vmExpression == null)
                    throw new ArgumentException("'propertyExpression' body should be a constant expression");

                // Create a reference to the calling object to pass it as the sender
                LambdaExpression vmlambda = Expression.Lambda(vmExpression);
                Delegate vmFunc = vmlambda.Compile();
                object vm = vmFunc.DynamicInvoke();

                // Extract the name of the property to raise a change on
                string propertyName = body.Member.Name;
                var e = new PropertyChangedEventArgs(propertyName);
                propertyChanged(vm, e);
            }
        }

        /// <summary>
        /// This method fires the PropertyChanged-Event
        /// </summary>
        /// <param name="name">The name of the variable which was changed</param>
        protected void NotifyPropertyChanged(string name)
        {
            if(PropertyChanged!=null)
                PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
        
        #endregion
    }

[LeftRightStackPanel] – How to create a custom WPF Container

Well today I needed a stackPanel which aligns my Buttons in a way such that it looks good 🙂

So I decided to extend StackPanel and implement my own functionality. If in vertical mode all even buttons should be on the left and all odd buttons (the second, fourth, sixth… button) should be at the right of the previous button.

If the orientation is the to vertical it looks like this:

LeftRightStackPanel-Vertical

If the Orientation is set to horizontal it looks like this

LeftRightStackPanel-Horizontal

First of all it is necessary to create a new class and extend StackPanel

public class LeftRightStackPanel : StackPanel
{
}

Now we have to implement the MeasureOverride and ArrangeOverride Methode.
The first will be called when it repaints the graphical user interface. In this method we have to measure the size which we need to place all controls.
In the ArrangeOverride method we have to position the controls (like we measured before).

Here you see a short example. It is this LeftRightStackPanel (but only the vertical view)

public class LeftRightStackPanel : StackPanel
{
  private readonly Size _infinite = new Size(Double.MaxValue,Double.MaxValue);

  protected override Size MeasureOverride(Size constraint)
  {
    Size resultSize = new Size(0, 0);
    //Measure the size we need for our modified StackPanel
    foreach (UIElement child in Children)
    {
      //Call the measure method of the childs
      //with the parameter we can specify the maximal size (the childs can use)
      //In our case we don't care about the size of the childs. We just arrange them in the StackPanel.
      child.Measure(_infinite);
      //Get the Width of the widest child
      resultSize.Width = Math.Max(resultSize.Width, child.DesiredSize.Width);
      //Add the height of each child to the total height
      resultSize.Height += child.DesiredSize.Height;
    }
    //Multiply the width by 2 because we have 2 buttons side by side
    resultSize.Width = resultSize.Width * 2;
    return resultSize;
  }

  protected override Size ArrangeOverride(Size finalSize)
  {
    double x = 0, y = 0;
    int count = 1;
    //Arrange the childs in the modified StackPanel
    foreach (UIElement child in Children)
    {
      //Arrange the child at x,y (the first will be at 0,0)
      child.Arrange(new Rect(x, y, child.DesiredSize.Width, child.DesiredSize.Height));
      //Determine the x value for the next child (even = left, odd = right)
      x = count % 2 == 0 ? 0 : child.DesiredSize.Width;
      //Determine the y value for the next child (below the acutal child)
      y += child.DesiredSize.Height;
      count++;
    }
    return finalSize;
  }
}

Allright the orientation = vertical works. Now we have to implement the functionality for the horizontal orientation.
So we have to check if Orientation is set to vertical or horizontal and then behave in a different way.
Here you see how it can be done.

public class LeftRightStackPanel : StackPanel
{
  private readonly Size _infinite = new Size(Double.MaxValue,Double.MaxValue);

  protected override Size ArrangeOverride(Size finalSize)
  {
    if (Orientation == Orientation.Vertical)
    {
      double x = 0, y = 0;
      int count = 1;

      foreach (UIElement child in Children)
      {
         child.Arrange(new Rect(x, y, child.DesiredSize.Width, child.DesiredSize.Height));

        x = count % 2 == 0 ? 0 : child.DesiredSize.Width;
        y += child.DesiredSize.Height;
        count++;
      }
    }
    else
    {
      double x = 0, y = 0;
      int count = 1;

      foreach (UIElement child in Children)
      {
        child.Arrange(new Rect(x, y, child.DesiredSize.Width, child.DesiredSize.Height));
        x += child.DesiredSize.Width;
        y = count % 2 == 0 ? 0 : child.DesiredSize.Height;
        count++;
      }
    }
    return finalSize;
  }

  protected override Size MeasureOverride(Size constraint)
  {
    if (Orientation == Orientation.Vertical)
    {
      Size resultSize = new Size(0, 0);

      foreach (UIElement child in Children)
      {
        child.Measure(_infinite);
        resultSize.Width = Math.Max(resultSize.Width, child.DesiredSize.Width);
        resultSize.Height += child.DesiredSize.Height;
      }

      resultSize.Width = resultSize.Width * 2;

      return resultSize;
    }
    else
    {
      Size resultSize = new Size(0, 0);

      foreach (UIElement child in Children)
      {
         child.Measure(_infinite);
         resultSize.Width += child.DesiredSize.Width;
         resultSize.Height = Math.Max(child.DesiredSize.Height, resultSize.Height);
       }

       resultSize.Height = resultSize.Height * 2;

       return resultSize;
    }
  }
}

This is the final sourcecode. You can use this control in the same way as you use the StackPanel.

Where is FolderBrowserDialog for WPF?

Well probably you needed a FolderBrowserDialog for WPF but there is not a built in FolderBrowserDialog like we know it of the WinForms technologie.
First of all you could use the WinForms Dialog but in my opinion it is better to use the WPF technologies if we are using WPF 🙂

So I was looking for a Control which contains this functionality.
After a few hours of searching and testing I found a library from Ookii, which contains even more than just a FolderBrowserDialog.
Check this out: http://www.ookii.org/software/dialogs/

Where is the DesignMode-Property in WPF?

If you want to implement a diffrent behaviour at design-time you can use the DesignMode Property in WinForms.
But in WPF does not exist this property.

So you have to use


public void DoSomethingOnlyAtRuntime()
{
  if(!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
      DoSomething();
}

Load image from Assembly

If you create a new CustomControl and want to load an image from the resources you can use this method.
Because in CustomContorls you can not load the image with the path, therefore you have to load it directyl from the assembly.

public static BitmapImage getImageFromAssembly(string filename)
{
  var path = string.Format("/MyAssembly;component/{0}", filename);
  var uri = new Uri(path, UriKind.Relative);
  var resourceStream = Application.GetResourceStream(uri);
  if (resourceStream == null)
    return null;

  var bitmap = new BitmapImage();
  bitmap.BeginInit();
  bitmap.StreamSource = resourceStream.Stream;
  bitmap.EndInit();
  return bitmap;
}
Advertisements