WPF PropertyGrid 绑定时间控件属性问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WPF PropertyGrid 绑定时间控件属性问题相关的知识,希望对你有一定的参考价值。

定义了一个类,在类里面有一个属性
private DateTime personAge;
[CategoryAttribute("PersonInfo"),
DisplayName("年龄"),
DescriptionAttribute("年龄"),
EditorAttribute(
typeof(PropertyGridDateItem),
typeof(System.Drawing.Design.UITypeEditor))]
public DateTime PersonAge

get return this.personAge;
set this.personAge = value;

这是自定义属性DatePicker的类
public class PropertyGridDateItem : UITypeEditor

MonthCalendar dp = new MonthCalendar();
public PropertyGridDateItem()

dp.MaxSelectionCount = 1;

public override UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)

return UITypeEditorEditStyle.DropDown;

public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, System.IServiceProvider provider, object value)

try

IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
if (edSvc != null)

if (value is string)

dp.SelectionStart = DateTime.Parse(value as String);
edSvc.DropDownControl(dp);
return dp.SelectionStart.ToShortDateString();

else if (value is DateTime)

dp.SelectionStart = (DateTime)value;
edSvc.DropDownControl(dp);
return dp.SelectionStart;



catch (Exception ex)

System.Console.WriteLine("PropertyGridDateItem Error : " + ex.Message);
return value;

return value;



但是为什么我点击下拉列表的时候不出来DatePicker呢?

WPF PropertyGrid 是官方的么?还是你用的Winform的PropertyGrid?
我从来没见过官方的PropertyGrid

我只知道PropertyGrid在WinForm下是这样写的,通过返回DropDown来控制
参考技术A 你的这个类是一个自定义控件么?追问

是的 !

追答

如果是自定义控件,那么对VS PropertyGrid的扩展只能通过对Designer的扩展来进行
你需要新建一个以控件所属的Assembly的名字+.Design结尾的工程,例如:MyControlLibrary.dll对应MyControlLibrary.Design.dll,编译结果放到同一个目录下
在这个Design工程中,用metadata来给控件属性设置editor,详见

http://msdn.microsoft.com/en-us/library/bb907382(v=vs.90).aspx

本回答被提问者采纳

只绑定WPF控件的margin属性的一部分

【中文标题】只绑定WPF控件的margin属性的一部分【英文标题】:Binding only part of the margin property of WPF control 【发布时间】:2011-09-09 02:55:50 【问题描述】:

我有这个:

<TabControl Margin="0,24,0,0">...</TabControl>

我只想绑定 TabControl 的 "Top" 部分,直觉上我会这样做:

<TabControl Margin="0,Binding ElementName=TheMenu, Path=Height,0,0">
 ...
</TabControl>

我该怎么做?

【问题讨论】:

【参考方案1】:

你试过用这样的转换器吗?

在 VB.Net 中

Public Class MarginConverter
  Implements IValueConverter

  Public Function Convert(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.Convert
    Return New Thickness(0, CDbl(value), 0, 0)
  End Function

  Public Function ConvertBack(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.ConvertBack
    Return Nothing
  End Function
End Class

或者在 C# 中

public class MarginConverter : IValueConverter


    public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
    
        return new Thickness(0, System.Convert.ToDouble(value), 0, 0);
    

    public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
    
        return null;
    

XAML

<Window.Resources>
    <local:MarginConverter x:Key="marginConverter"></local:MarginConverter>
</Window.Resources>
<Grid>
    <StackPanel>
        <Slider Name="Slider1"></Slider>
        <TabControl Name="TabControl" Margin="Binding ElementName=Slider1, Path=Value, Converter=StaticResource marginConverter">
            <Button>Some content</Button>
        </TabControl>
    </StackPanel>
</Grid>

编辑:使用 MultiConverter

还可以在运行时获取所有四个值并使用 MultiValueConverter。 Thickness-Object 的 Top-Property 不是 Dependency-Object,因此您不能定义对它的绑定(除非您的源不是 Dependency-Object)。

XAML

<Window.Resources>
    <local:MarginConverter x:Key="marginConverter"></local:MarginConverter>
    <local:MultiMarginConverter x:Key="multiMarginConverter"></local:MultiMarginConverter>
</Window.Resources>
<Grid>
    <StackPanel>
        <Slider Name="Slider1"></Slider>
        <Slider Name="Slider2"></Slider>
        <Slider Name="Slider3"></Slider>
        <Slider Name="Slider4"></Slider>
        <TabControl Name="TabControl">
            <TabControl.Margin>
                <MultiBinding Converter="StaticResource multiMarginConverter">
                    <Binding ElementName="Slider1" Path="Value"></Binding>
                    <Binding ElementName="Slider2" Path="Value"></Binding>
                    <Binding ElementName="Slider3" Path="Value"></Binding>
                    <Binding ElementName="Slider4" Path="Value"></Binding>
                </MultiBinding>
            </TabControl.Margin>
            <Button>Some content</Button>
        </TabControl>
    </StackPanel>
</Grid>

...和c#

  class MultiMarginConverter : IMultiValueConverter
  
    public object Convert(object[] values, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
    
      return new Thickness(System.Convert.ToDouble(values[0]),
                           System.Convert.ToDouble(values[1]),
                           System.Convert.ToDouble(values[2]),
                           System.Convert.ToDouble(values[3]));
    

    public object[] ConvertBack(object value, System.Type[] targetType, object parameter, System.Globalization.CultureInfo culture)
    
      return null;
    
  

编辑(2) 反向绑定: 我不确定这是否会让你开心。以我的拙见,我会尽量避免这种情况,但是好的......如果你的源是依赖属性,你可以将它绑定到边距:

<Slider Name="Slider5" Minimum="-99" Maximum="0" Value="Binding ElementName=TabControl, Path=Margin.Top, Mode=OneWayToSource"></Slider>

但我对此有一些影响。 诀窍是,您不要将 TabControl 的 Margin 的一部分绑定到“其他”,而是将“其他”绑定到 TabControl 的 Margin 并指定 Binding-Mode OneWayToSource

【讨论】:

但是这种方式迫使我在代码中输入所有其他数字,没有办法在标记中使用子标签,例如:&lt;TabControl.Margin.Thikness.Top="Binding..."...&gt; 查看编辑了解 MultiValueConverter 的详细信息和建议。顶部(和底部和....)没有依赖属性。对于 Binding,至少有一部分必须是 Dependency-Property。 我注意到,将FallBackValue 添加到Binding 时,它会在传递给MultiMarginConverter 之前转换为Thickness,这会导致它出错。有什么可以防止这种情况发生,还是我必须在转换器中将其拆开?【参考方案2】:

你可以尝试类似this answer from another question。

该解决方案使用允许 XAML 的附加属性,如下所示:

<Button ap:MoreProps.MarginRight="10" />

附加属性也由 DependencyObject 支持,因此数据绑定将起作用。

【讨论】:

这是最好的答案,允许累积独立的边距绑定,并且在我读到的所有相关线程中唯一提供此功能的答案。 比最佳答案要好得多,因为它是一种自然、合乎逻辑的方法。谢谢!【参考方案3】:

从您的代码中,我认为您的菜单和 tabControl 可能重叠,因此您想使用边距将它们分开。我感觉这种做法像两列 CSS Layout。

言归正传,我觉得你可以申请TranslateFransformTabControl.RenderTransform。可以绑定Y属性。

【讨论】:

【参考方案4】:

实际上一个控件的Margin属性是Thickness类型。所以我们可以将它绑定到 Property if type Thickness。

 public Thickness LeftMargin  get; set; 

您也可以设置厚度对象的一部分。喜欢 -

 LeftMargin = new Thickness(20,0,0,0);

Xaml 中,我们可以将此属性直接绑定到任何元素的边距属性......就像这样......

 <TextBlock Text="Some Text"  Margin="Binding LeftMargin"  />

【讨论】:

我认为如果你只有 一个 面要绑定,这是正确的方法。否则,如果您需要为控件边距的每一侧设置不同的值,则需要其他选项。 @heltonbiker 我觉得挺好的,你可以分别设置left、right、top和bottom,用不同的值。 @CularBytes 我猜他的意思是,如果您需要将每一侧绑定到不同的属性。这不能仅使用一个Margin 属性来完成。据我所知,MultiBinding 是唯一的方法。 查看我的答案以获得绑定多个边距属性的简单解决方案。【参考方案5】:

如果您不附加到另一个 WPF 元素,则扩展 Ioop 的方法来控制边距而不是转换器:

创建 4 个标准属性和一个只读属性,就像这样-

Public Class CustomMargin
    Implements INotifyPropertyChanged

    Private _Left As Double
    Private _Right As Double
    Private _Up As Double
    Private _Down As Double

    Public Sub New()
      _Up = 0
      _Down = 0
      _Left = 0
      _Right = 0
    End Sub

    Public Sub New(Vertical as Double, Horizontal as Double)
      _Up = Vertical
      _Down = Vertical
      _Left = Horizontal
      _Right = Horizontal
    End Sub

    Public Sub New(Left as Double, Up as Double, Right as Double, Down as Double)
      _Up = Up
      _Down = Down
      _Left = Left
      _Right = Right
    End Sub

    Public Property Left As Double
        Get
            Return _Left
        End Get
        Set(value As Double)
            _Left = value
            OnPropertyChanged(New PropertyChangedEventArgs("MyMargin"))
        End Set
    End Property

    Public Property Right As Double
        Get
            Return _Right
        End Get
        Set(value As Double)
            _Right = value
            OnPropertyChanged(New PropertyChangedEventArgs("MyMargin"))
        End Set
    End Property

    Public Property Up As Double
        Get
            Return _Up
        End Get
        Set(value As Double)
            _Up = value
            OnPropertyChanged(New PropertyChangedEventArgs("MyMargin"))
        End Set
    End Property

    Public Property Down As Double
        Get
            Return _Down
        End Get
        Set(value As Double)
            _Down = value
            OnPropertyChanged(New PropertyChangedEventArgs("MyMargin"))
        End Set
    End Property

    Public ReadOnly Property MyMargin As Thickness
        Get
            Return New Thickness(Left, Up, Right, Down)
        End Get
    End Property

    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged

    Public Sub OnPropertyChanged(ByVal e As PropertyChangedEventArgs)
        If Not PropertyChangedEvent Is Nothing Then
            RaiseEvent PropertyChanged(Me, e)
        End If
    End Sub
End Class

然后你只需要添加XAML-

<Label x:Name="MyLabel" Margin="Binding Path=MyMargin, FallbackValue=0 0 0 0, Mode=OneWay"/>

然后在WPF窗口后面的代码上-

Private _NewMargin as New CustomMargin

Public Sub New()
  InitializeComponent()
  MyLabel.DataContext = _NewMargin
End Sub

从那里您可以使用任何您希望单独更改所有 4 个边距的控件,Class 可重复用于其他控件。

【讨论】:

【参考方案6】:

我只在 StackPanel 中使用了这种解决方法来处理左边距。好处是你不需要任何转换器。

<DockPanel VerticalAlignment="Top">
  <TextBlock Name="tbkFulltextCaption"
             Text="Static Caption:"
             DockPanel.Dock="Left" />
  <StackPanel Orientation="Horizontal"
              DockPanel.Dock="Bottom">
      <FrameworkElement Name="feLeftMargin"
                        Width="Binding Width, ElementName=tbkFulltextCaption, Mode=OneWay" />
      <TextBlock Text="(some text with margin of tbkFulltextCaption.Width)"
                 Name="tbkUnderNonsense" 
                 FontSize="8"                                       
                 Foreground="Gray">
      </TextBlock>
  </StackPanel>
  <TextBox Name="tbFulltextSearch" />
</DockPanel>

preview

【讨论】:

【参考方案7】:

好的,它很旧,但我正在寻找更好的方法:

<TabControl>
    <TabControl.Margin>
        <Thickness Top="Binding ElementName=TheMenu, Path=Height" />
     </TabControl.Margin>
</TabControl>

【讨论】:

这不起作用,你会得到:“不能在'Thickness'类型的'Top'属性上设置'Binding'。” 确实如此——肯定有不同的原因......也许你可以发布你的代码。 @Paul 是正确的,您不能设置与 Thickness 的 Top 属性的绑定,因为它不是 DependencyProperty,而 Thickness 也不是 DependencyObject。 我过去用过 - 框架有什么变化吗? @Athanviel 我一直尝试回到 .NET Framework 3.0(支持 WPF 的最早的 .NET 版本),但即使在那时也无法正常工作

以上是关于WPF PropertyGrid 绑定时间控件属性问题的主要内容,如果未能解决你的问题,请参考以下文章

C#中自定义propertygrid控件的属性,要求当点击不同的其他控件时,能在propertygrid控件中显示基本的信息

c#怎么利用combbox控件,切换propertygrid1下绑定的类

4-PropertyGrid绑定自定义弹窗

wpf控件设计时支持

WPF。查找绑定到特定属性的控件

wpf 控件属性通过数据绑定到某个集合的某一个数据上。