tags:

views:

189

answers:

3

Hi all. I'm pretty new to WPF so excuse me for any dumb question...

I have a ListView with three columns that is binded to a XmlDataProvider source like the following:

        <XmlDataProvider x:Key="Properties" XPath="/Info">
        <x:XData>
            <Info xmlns="">
                <Property Name="Text" Value=""/>                <!--0-->
                <Property Name="Tooltip" Value=""/>             <!--1-->
                <Property Name="Enable" Value=""/>              <!--2-->
                <Property Name="Visible" Value=""/>             <!--3-->
                <Property Name="Focus" Value=""/>               <!--4-->
                <Property Name="Selected" Value=""/>            <!--5-->
                <Property Name="Count" Value=""/>               <!--6-->
                <Property Name="Item" Value=""/>                <!--7-->
                <Property Name="SelectedText" Value=""/>        <!--8-->
                <Property Name="SelectedIndex" Value=""/>       <!--9-->
                <Property Name="Complete" Value=""/>            <!--10-->
            </Info>
        </x:XData>
    </XmlDataProvider>

The ListView is defined as following:

        <ListView Name="lstProperties"  Margin="55 0 0 0" Style="{DynamicResource TsListView}"
        Grid.Row="2" Grid.RowSpan="7" Grid.ColumnSpan="4"
        ItemsSource="{Binding Source={StaticResource Properties}, XPath=Property}" 
        ItemContainerStyle="{DynamicResource TsListViewItem}" 
        ScrollViewer.HorizontalScrollBarVisibility="Hidden"
        SelectionMode="Single" IsEnabled="False"
        SelectionChanged="propertySelected" 
        >

        <ListView.View>
            <GridView AllowsColumnReorder="False">
                <GridViewColumn CellTemplate="{StaticResource FirstCell}" Width="25" />
                <GridViewColumn Header="Property" Width="80">
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <Label Style="{DynamicResource TsLabel}" Height="25" Width="115" Content="{Binding XPath=@Name}" />
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                <GridViewColumn Header="Value" Width="130">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <TextBox Style="{DynamicResource TsHelperTextBox}"
                                     Height="20" Width="115" Text="{Binding XPath=@Value}" 
                                     IsEnabled="{Binding ElementName=rbTypeAssert, Path=IsChecked}" GotFocus="gridTextBox_GotFocus" />
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
            </GridView>
        </ListView.View>
    </ListView>

What I want to do now is fairly simple: I just want to enable/disable some of the ListViewItems. The only way I found to get ListViewItems is through the following method:

lstProperties.ItemContainerGenerator.ContainerFromIndex(index)

This makes me a little uncomfortable. I should be getting the Items through the name property of Property. Is there anyway to do this? I'm also having problems when I try to do this right after the window is initialized. I get a NullReferenceException when trying to disable one of these ListViewItems. It seems that right after the window is rendered the binding is not done yet.

+1  A: 

The easiest and best way to do this is to expose a property that determines whether the ListViewItem should be enabled or not, and then bind to it:

<ListView>
    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <Setter Property="IsEnabled" Value="{Binding YourProperty}"/>
        </Style>
    </ListView.ItemContainerStyle>
</ListView>

HTH,
Kent

Kent Boogaart
Thanks, I've thought of something like this but I had three problemswith this approach.1. How to define a custom Property (OK this is really a newbie question)2. I already have a style defined for all the ListViewItems on my application. Does your solution means that I have to have a specific style for these ListViewItems?, and most important, 3. In this particular situation I need one property per ListViewItem and not one general property. Can I bind this from the XmlDataSource?Thanks
jpsstavares
A: 

Well your feedback, combined with other feedback received, allowed me to solve the problem. Thanks very much!

What I did was to add a new attribute, named IsEnable, to the Property in the XmlDataProvider, and then I binded the IsEnabled property of the ListViewItem to this new attribute. So instead of having one global property to define the state of all the ListViewItems, like you suggested, I'll have "individual binds".

To change the data programmatically I used the following method:

provider.Document.SelectSingleNode("//Property[Name=\"Text\"]/IsEnable").InnerText = false.ToString();

This method requires a slightly different format for the data. So the XmlDataProvider is now as following:

        <XmlDataProvider x:Key="Properties" XPath="/Info" IsAsynchronous="False" IsInitialLoadEnabled="True">
        <x:XData>
            <Info xmlns="">
                <Property>
                    <Name>Text</Name>
                    <Value></Value>
                    <IsEnable>true</IsEnable>
                </Property>
                <Property>
                    <Name>Tooltip</Name>
                    <Value></Value>
                    <IsEnable>true</IsEnable>
                </Property>
                <Property>
                    <Name>Enable</Name>
                    <Value></Value>
                    <IsEnable>true</IsEnable>
                </Property>
                <Property>
                    <Name>Visible</Name>
                    <Value></Value>
                    <IsEnable>true</IsEnable>
                </Property>
                <Property>
                    <Name>Focus</Name>
                    <Value></Value>
                    <IsEnable>true</IsEnable>
                </Property>
                <Property>
                    <Name>Selected</Name>
                    <Value></Value>
                    <IsEnable>true</IsEnable>
                </Property>
                <Property>
                    <Name>Count</Name>
                    <Value></Value>
                    <IsEnable>true</IsEnable>
                </Property>
                <Property>
                    <Name>Item</Name>
                    <Value></Value>
                    <IsEnable>true</IsEnable>
                </Property>
                <Property>
                    <Name>SelectedText</Name>
                    <Value></Value>
                    <IsEnable>true</IsEnable>
                </Property>
                <Property>
                    <Name>SelectedIndex</Name>
                    <Value></Value>
                    <IsEnable>true</IsEnable>
                </Property>
                <Property>
                    <Name>Complete</Name>
                    <Value></Value>
                    <IsEnable>true</IsEnable>
                </Property>
            </Info>
        </x:XData>
    </XmlDataProvider>

Thanks again for your contribution! José Tavares

jpsstavares
+1  A: 

Kents answer is correct, but I would use a converter, instead of expanding your model:

<ListView>
    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <Setter Property="IsEnabled" Value="{Binding Converter={StaticResource IsEnabledConverter}}"/>
        </Style>
    </ListView.ItemContainerStyle>
</ListView>

And the converter:

public class IsEnabledConverter : IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        //Implement your logic here, and return true/false accordingly
        return true;
    }

    public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new System.NotImplementedException();
    }

    #endregion
}
Arcturus
Well I see this working though I think I prefer the solution I obtained because the bind is clearer and it doesn't involve additional code. But thanks for the tip, it may be use useful for me in other situations.
jpsstavares