C# WPF-使用RelativeSource绑定为自定义标记扩展提供设计时值

C# WPF-使用RelativeSource绑定为自定义标记扩展提供设计时值,c#,wpf,xaml,binding,markup-extensions,C#,Wpf,Xaml,Binding,Markup Extensions,N.B.:这不仅仅是关于自定义标记扩展。请在标记为副本之前阅读。 我有一个带有转换器的WPF标记扩展,其中两个如下所示: [ValueConversion(typeof(WindowState), typeof(object))] internal class WindowStateToObjectConverter : IValueConverter { public WindowStateToObjectConverter() { } public WindowSt

N.B.:这不仅仅是关于自定义标记扩展。请在标记为副本之前阅读。

我有一个带有转换器的WPF标记扩展,其中两个如下所示:

  [ValueConversion(typeof(WindowState), typeof(object))]
  internal class WindowStateToObjectConverter : IValueConverter {
    public WindowStateToObjectConverter() { }

    public WindowStateToObjectConverter(object maximized, object normal) {
      this.maximized = maximized;
      this.normal = normal;
    }

    #region Properties
    #region Maximized Property
    private object maximized;

    public object Maximized {
      get { return maximized; }
      set { maximized = value; }
    }
    #endregion
    #region Normal Property
    private object normal;

    public object Normal {
      get { return normal; }
      set { normal = value; }
    }
    #endregion
    #endregion

    public object Convert(object value, Type targetType, object param, CultureInfo culture) {
      if((value as WindowState? ?? WindowState.Normal) == WindowState.Maximized) return maximized;
      else return normal;
    }

    public object ConvertBack(object value, Type targetType, object param, CultureInfo culture) {
      throw new InvalidOperationException("Cannot convert downwards to WindowState");
    }
  }

  [MarkupExtensionReturnType(typeof(Binding))]
  internal class WindowMaximizedSwitchExtension : MarkupExtension {
    object maximized, normal;

    public WindowMaximizedSwitchExtension(object maximized, object normal) {
      this.maximized = maximized;
      this.normal = normal;
    }

    public override object ProvideValue(IServiceProvider serviceProvider) {
      Binding ret = new Binding("WindowState");
      RelativeSource retRSource = new RelativeSource(RelativeSourceMode.FindAncestor);
      retRSource.AncestorType = typeof(Window);
      ret.RelativeSource = retRSource;
      ret.Converter = new WindowStateToObjectConverter(maximized, normal);
      return ret.ProvideValue(serviceProvider);
    }
  }
它们用于我正在设计的自定义窗口-当窗口最大化时,它们将用于切换某些值(边框宽度、边距等)。但是,在设计时,它们总是返回null,这是一个真正的难题,因为我的窗口如下所示:

public override object ProvideValue(IServiceProvider serviceProvider) {
  Binding ret = new Binding("WindowState");
  RelativeSource retRSource = new RelativeSource(RelativeSourceMode.FindAncestor);
  retRSource.AncestorType = typeof(Window);
  ret.RelativeSource = retRSource;
  ret.Converter = new WindowStateToObjectConverter(maximized, normal);
  ret.FallbackValue = normal;
  return ret.ProvideValue(serviceProvider);
}

…当它看起来像这样的时候:

public override object ProvideValue(IServiceProvider serviceProvider) {
  Binding ret = new Binding("WindowState");
  RelativeSource retRSource = new RelativeSource(RelativeSourceMode.FindAncestor);
  retRSource.AncestorType = typeof(Window);
  ret.RelativeSource = retRSource;
  ret.Converter = new WindowStateToObjectConverter(maximized, normal);
  ret.FallbackValue = normal;
  return ret.ProvideValue(serviceProvider);
}

(忽略第一张图片中缺少标题和图标,不过,如果您有解决方案,请随意回答-这基本上是同一个问题。)


出于显而易见的原因,用这个进行设计是非常困难的。您在窗口预览中看到的唯一主要问题是我使用扩展设置
/
列定义
s的位置-当它返回null时,
高度
/
宽度
设置为
1*
。因此,我的问题是,是否有一种方法可以在设计时选择默认值,而不是绑定(例如,非最大化值)。

嗯,我觉得自己像个白痴,但我很快找到了解决方案:

在表达式的
ProvideValue
方法中,我添加了以下行:

  ret.FallbackValue = normal;
其中
normal
是窗口未最大化时使用的值

ProvideValue
现在看起来是这样的:

public override object ProvideValue(IServiceProvider serviceProvider) {
  Binding ret = new Binding("WindowState");
  RelativeSource retRSource = new RelativeSource(RelativeSourceMode.FindAncestor);
  retRSource.AncestorType = typeof(Window);
  ret.RelativeSource = retRSource;
  ret.Converter = new WindowStateToObjectConverter(maximized, normal);
  ret.FallbackValue = normal;
  return ret.ProvideValue(serviceProvider);
}

这将在设计期间返回正常值。

我很惊讶我没有在网上找到这个答案……你可能会认为人们会发布/询问这个问题。再说一次,大多数人不是自学成才的。