Resharper says OnPropertyChange set member can be

2019-07-06 06:50发布

I use C#, MVVM, WPF and Resharper.

When using the following code:

    public bool CombiBanksSelected
    {
        get { return _selectedBanksType == ESelectedBanksType.CombiBanks; }
        set
        {

I get a warning of Resharper: Make set accessor private.

When making the set method private, I get an InvalidOperationException: A TwoWay or OneWayToSource binding cannot work on the read-only property ''CombiBanksSelected'' of type ''PcgTools.ViewModels.PcgViewModel.'

Of course I can suppress it by adding:

    public bool CombiBanksSelected
    {
        get { return _selectedBanksType == ESelectedBanksType.CombiBanks; }
// ReSharper disable MemberCanBePrivate.Global
        set
// ReSharper restore MemberCanBePrivate.Global
        {

But this is not looking nice and not feeling good. Is there a better alternative or solution for this problem?

According to the answer I should change the XAML code. Mine is:

<UserControl x:Class="PcgTools.PcgWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ViewModels="clr-namespace:PcgTools.ViewModels" Height="Auto" Width="Auto" 
    Loaded="Window_Loaded">

<Grid>
  ...
    <RadioButton Content="_Programs" Height="16" HorizontalAlignment="Left" Margin="12,12,0,0" Name="radioButtonPrograms" VerticalAlignment="Top" 
                 IsChecked="{Binding Path=ProgramBanksSelected}" IsEnabled="{Binding Path=ProgramsEnabled}"/>
    <RadioButton Content="_Combis" Height="16" HorizontalAlignment="Left" Margin="85,12,0,0" Name="radioButtonCombis" VerticalAlignment="Top" 
                 IsChecked="{Binding Path=CombiBanksSelected}"  IsEnabled="{Binding Path=CombisEnabled}"/>

I have the Resharper problem for both (and more) properties binded to IsChecked (ProgramBanksSelected and CombiBanksSelected in the code above).

In the answer is shown that I should use a DataTemplate, but I still can't figure out how exactly (with not using MVVM light's Locator).

How should I use the data context/template?

3条回答
Animai°情兽
2楼-- · 2019-07-06 07:33

resharper is a great tool... but it can be wrong occasionally.

You should not annotate your source code with comments to please resharper. Or any other tool for that matter. The tool is wrong, so dont fix the code, fix the tool.

So tell resharper to ignore it. Right click on the icon in the leftmargin and tell it to ignore this kind of problem going forward, or put it in the hint category. I like that option because you can still acess the solution, if it applies, but r# does not show it in the graphical summary on the right.

查看更多
ら.Afraid
3楼-- · 2019-07-06 07:40

Resharper doesn't have enough information to deduce the setter is being used. For example:

This code:

public partial class Page2
{
    public Page2()
    {
        InitializeComponent();

        DataContext = new List<ViewModel>
                          {
                              new ViewModel()
                          };
    }
}

public class ViewModel : ViewModelBase
{
    private bool _combiBanksSelected;
    public bool CombiBanksSelected
    {
        get { return _combiBanksSelected; }
        set
        {
            Set(()=>CombiBanksSelected, ref _combiBanksSelected, value);
        }
    }
}

with this Xaml:

<Grid>
    <Grid.Resources>
        <DataTemplate x:Key="Template" >
            <CheckBox IsChecked="{Binding CombiBanksSelected}"/>
        </DataTemplate>
    </Grid.Resources>
    <ListBox ItemsSource="{Binding}" ItemTemplate="{StaticResource Template}" />
</Grid>

will show the setter as not being used (when SWA is turned on).

However if you change the Xaml (adding DataType="{x:Type Samples:ViewModel}") to:

<Grid>
    <Grid.Resources>
        <DataTemplate x:Key="Template" DataType="{x:Type Samples:ViewModel}">
            <CheckBox IsChecked="{Binding CombiBanksSelected}"/>
        </DataTemplate>
    </Grid.Resources>
    <ListBox ItemsSource="{Binding}" ItemTemplate="{StaticResource Template}" />
</Grid>

R# now has enough information and doesn't show the warning.

Of course there are other ways of giving R# and VS Intellisense more hints about the types you're using. Examples are:

Using MVVM Light's view locator:

<UserControl ...
    DataContext="{Binding AViewModel, Source={StaticResource Locator}}" />

Using d:DataContext. I recommend looking a this MSDN walkthrough

<UserControl ...
    d:DataContext="{d:DesignInstance AViewModel, IsDesignTimeCreatable=true}"

Explicitly setting the DataContext

<UserControl.Resources>
    <AViewModel x:Key="theModel/>
</UserControl.Resources>

<Grid DataContext="{StaticResource theModel}"> ...

etc...

Any of these methods allow R# and VS to infer the use of types and provide intellisense.

查看更多
Anthone
4楼-- · 2019-07-06 07:45

In addition to Phil's excellent suggestions, you can also use the UsedImplicitlyAttribute. You can use Nuget to do add the dll for you

enter image description here

And then R# will itself offer to decorate the setter with the attribute:

public bool CombiBanksSelected
{
    get { return _selectedBanksType == ESelectedBanksType.CombiBanks; }
    [UsedImplicitly] set
    {

I find it less noisy than a comment, and well suited to a ViewModel where it's understood that data bindings are typically unknown to R#. (sometimes I actually prefer a comment to remind me why I wanted R# to shut up, but not in this case).

Cheers,
Berryl

查看更多
登录 后发表回答