选择已具有绑定的画布上的路径

时间:2014-09-16 15:16:48

标签: c# wpf xaml canvas mvvm

我对WPF还有点新意,所以如果有一两个明显的概念我不知道,我会道歉。

我在MVVM范例之后使用WPF。我的真正问题有点复杂,所以我会尽量简化。假设我在画布上有一些(实际上是很多)路径:

<Canvas x:Name="Canvas1" Width="600" Height="300">
   <Path x:Name="Path1" Style="{StaticResource PathStyle}" .../>
   <Path x:Name="Path2" Style="{StaticResource PathStyle}" .../>
   <Path x:Name="Path3" Style="{StaticResource PathStyle}" .../>
/>

我使用的那种风格保留了一些绑定,使所有路径保持相同的颜色,如下所示:

<Style x:Key="PathStyle" TargetType="Path">
    <Setter Property="Fill" Value="{Binding FillColor, Converter={StaticResource BrushConverter}}"/>
    <Setter Property="Stroke" Value="{Binding StrokeColor, Converter={StaticResource BrushConverter}}"/>
</Style>

我可以在用户点击其中一条路径时捕获。当他们这样做时,我想&#34;覆盖&#34;绑定并更改所述路径的颜色,直到用户单击另一个。我可以在点击它时手动设置Path.Stroke,但我不知道如何重新激活&#34;一旦我清除了SelectedPath(因此路径保持我设置的任何颜色)。我已尝试获取绑定表达式以强制刷新,但返回值为null(selectedPath.GetBindingExpression(Path.StrokeProperty))。

TL; DR:我想在用户点击路径时这样做,它变成蓝色。当点击另一条路径时,我希望它根据样式中的绑定返回到所谓的的任何颜色。

有什么想法?谢谢你花时间!

编辑:感谢您提供可靠的建议 - 如果我可以再多推一遍,如果有嵌套画布会怎样,但我仍然只想选择一条路径?如:

<Canvas x:Name="Canvas_Main" Width="600" Height="300">
   <Canvas x:Name="Canvas1" Width="600" Height="300">
      <Path x:Name="Path1" Style="{StaticResource PathStyle}" .../>
      <Path x:Name="Path2" Style="{StaticResource PathStyle}" .../>
      <Path x:Name="Path3" Style="{StaticResource PathStyle}" .../>
   />
   <Canvas x:Name="Canvas1" Width="600" Height="300">
      <Path x:Name="Path1" Style="{StaticResource PathStyle}" .../>
      <Path x:Name="Path2" Style="{StaticResource PathStyle}" .../>
      <Path x:Name="Path3" Style="{StaticResource PathStyle}" .../>
   />
/>

2 个答案:

答案 0 :(得分:3)

以下内容:

  1. 使用ListBox,它提供项目选择。
  2. 将您的路径移至ListBox或绑定ListBox.ItemsSource
  3. ListBox.ItemsPanel设置为Canvas
  4. 在路径样式中引入在DataTrigger
  5. 上触发的{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListBoxItem}}
  6. 向触发器添加Setter,根据需要更改所选路径的颜色。
  7. (如果默认情况下看起来很奇怪,请添加ListBox.ItemContainerStyle以覆盖ListBoxItem.Template。)

  8. 编辑:好奇它是否按预期工作,所以这是一个独立的例子:

    <ListBox Height="300" Width="300">
        <ListBox.Resources>
            <Style TargetType="Path">
                <Setter Property="Stroke" Value="Black"/>
                <Setter Property="Fill" Value="Red"/>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListBoxItem}}"
                                 Value="True">
                        <Setter Property="Fill" Value="Blue"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </ListBox.Resources>
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas/>
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
        <ListBox.ItemContainerStyle>
            <Style TargetType="ListBoxItem">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="ListBoxItem">
                            <ContentPresenter />
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </ListBox.ItemContainerStyle>
        <Path>
            <Path.Data>
                <RectangleGeometry Rect="50,50,25,25" />
            </Path.Data>
        </Path>
        <Path>
            <Path.Data>
                <RectangleGeometry Rect="0,0,25,25" />
            </Path.Data>
        </Path>
    </ListBox>
    

答案 1 :(得分:1)

此方法也使用ListBox,但使用ListBoxItem的BackgroundBorderBrush属性作为路径的FillStroke

<ListBox ItemsSource="{Binding PathItems}">
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas/>
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <Setter Property="Background" Value="Azure"/>
            <Setter Property="BorderBrush" Value="Black"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ListBoxItem">
                        <Path Data="{Binding Geometry}"
                              Fill="{TemplateBinding Background}"
                              Stroke="{TemplateBinding BorderBrush}"
                              StrokeThickness="3"/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="Background" Value="Pink"/>
                    <Setter Property="BorderBrush" Value="Red"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

它假设有一个这样的视图模型:

public class PathItem
{
    public Geometry Geometry { get; set; }
}

public class ViewModel
{
    public ObservableCollection<PathItem> PathItems { get; set; }
}

如果视图模型也应提供所选状态和未选择状态的填充和描边,则通常会在项目级别定义它们,例如如下所示(这也可以让您选择个性化)每件商品的颜色或画笔。

public class PathItem
{
    public Geometry Geometry { get; set; }
    public Brush UnselectedFill { get; set; }
    public Brush UnselectedStroke { get; set; }
    public Brush SelectedFill { get; set; }
    public Brush SelectedStroke { get; set; }
}

然后绑定到ItemContainerStyle中的那些属性:

<Style TargetType="ListBoxItem">
    <Setter Property="Background" Value="{Binding UnselectedFill}"/>
    <Setter Property="BorderBrush" Value="{Binding UnselectedStroke}"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ListBoxItem">
                <Path Data="{Binding Geometry}"
                      Fill="{TemplateBinding Background}"
                      Stroke="{TemplateBinding BorderBrush}"
                      StrokeThickness="3"/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <Trigger Property="IsSelected" Value="True">
            <Setter Property="Background" Value="{Binding SelectedFill}"/>
            <Setter Property="BorderBrush" Value="{Binding SelectedFill}"/>
        </Trigger>
    </Style.Triggers>
</Style>