【问题标题】:Changing protection level of newly created object?更改新创建对象的保护级别?
【发布时间】:2016-11-02 16:53:37
【问题描述】:

好吧,所以我很幸运遇到了很多基本问题。我无法解决这个特定问题。

这段代码需要访问“MainWindow”类中创建的对象的“_Player.Name”属性。

编辑:这次放上整个代码。这是字符串所在的 Code_Behind。

public class Code_Behind
{

    private static string _Name = "Default";
    public class Player
    {
        public void setName(string name) //Ignore this part, was trying to find a work around here
        {
            _Name = name;
        }
        public string Name
        {
            get { return _Name; }
            set
            {
                _Name = value;
            }
        }
    }
    //contentControl is used to store Content properties
    //UI elements are bound to Content properties to efficiently change their Content
    public class contentControl : INotifyPropertyChanged
    {
        protected void OnPropertyChanged(string name)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
        public void setEvent(string Event)
        {
            textBoxContent = Event;
        }
        public void addEvent(string Event)
        {
            textBoxContent +="\n" + Event;
        }
        public class Events
        {
            public string EV001 = String.Format("\"Greetings {0}. What can I do for you today?\"", window.PlayerName);
        }
}

这是主窗口:

public partial class MainWindow : Window
{
    Code_Behind.contentControl cC = new Code_Behind.contentControl();
    Code_Behind.contentControl.Events Events = new Code_Behind.contentControl.Events();
    Code_Behind.Player _Player = new Code_Behind.Player();
    public string GetPlayerName()
    {
        return _Player.Name;
    }
    public static string _name = "null";
    public MainWindow()
    {
        this.DataContext = cC;
        InitializeComponent();
    }

【问题讨论】:

  • public Code_Behind.Player _Player = new Code_Behind.Player(); ?
  • EV001 不是一个好的成员名称。考虑一些更具可读性和自我描述性的东西。
  • 您无法更改对象的保护级别,因为对象没有保护级别。字段和变量可以。 tym32167 有一个答案; mybirthname 有一个更好的。我的是最好的:public String PlayerName { get { return _Player.Name; } }
  • @tym32167 不,遗憾的是,这最终会导致错误 CS0120:非静态字段、方法或属性“MainWindow._Player”需要对象引用
  • @Zephylir 您可以将其设为public static ...,但不确定这是否正是您在这种情况下所需要的。

标签: c# wpf object string.format


【解决方案1】:
public string GetPlayerName()
{
    return _Player.Name
}

MainWindow 类中创建一个方法。之后你调用这个方法。

public string EV001 = String.Format("\"Greetings {0}. What can I do for you today?\"", 
                       window.GetPlayerName());

如果你愿意,你也可以用属性来做到这一点。

public string PlayerName
{
    get { return _Player.Name; };
}

【讨论】:

  • 这将是一个很好的解决方案,但由于某种原因,当我使用“MainWindow.GetPlayerName()”时它会触发 CS0120
  • @Zephylir 你应该创建 MainWindow 对象。
  • @Zephylir 你认为通过阅读错误消息的文本可能会阐明这个神秘的原因吗?
  • @mybirthname 我认为他需要访问现有的MainWindow 实例,而不是创建一个新实例。
  • @EdPlunkett 是的,如果他已经拥有该窗口的实例,请接受它。但在他的代码中我没有看到。我想他从来没有创造过它。
【解决方案2】:

您在这里遇到的更大问题不是可访问性,而是不了解类和对象之间的区别。

MainWindow 是一个类。它不代表任何特定的窗口。把一个类想象成一个创建对象的食谱。如果你有巧克力曲奇的食谱,你不会吃这个食谱,你会吃一个特定的饼干或按照那个食谱烘焙的饼干。

您的其他班级首先需要知道您尝试从哪个特定窗口获取玩家名称。它需要一个对特定 MainWindow 对象的引用。

【讨论】:

    【解决方案3】:

    看起来你正在尝试编写类似于视图模型的东西:你有一个玩家,他有一个名字,还有一个你认为是“事件”的字符串集合。我不明白“事件”是什么意思,但我对我认为你似乎试图做的事情进行了我的最佳猜测。

    至于这个:

        public class Events
        {
            public string EV001 = String.Format("\"Greetings {0}. What can I do for you today?\"", window.PlayerName);
        }
    

    我猜你在某处创建了一个MainWindow 的实例,并将其命名为window,但它是在某处定义的,它对该行代码“超出范围”。以此类推,你看不到下一座山后面的任何东西,只能看到你所在的山谷中的东西。这大致(非常粗略,抱歉)范围是关于什么的。

    但是,让我们继续猜测您要做什么。这会构建、运行和工作。有任何问题,开火。

    ViewModels.cs

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Player
    {
        public class ViewModelBase : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
    
            protected void OnPropertyChanged(string name)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
            }
        }
    
        public class MainViewModel : ViewModelBase
        {
            #region Player Property
            private PlayerViewModel _player = default(PlayerViewModel);
            public PlayerViewModel Player
            {
                get { return _player; }
                set
                {
                    if (value != _player)
                    {
                        _player = value;
                        OnPropertyChanged(nameof(Player));
                        //  Change the player for all the existing events.
                        foreach (var e in Events)
                        {
                            e.Player = Player;
                        }
                    }
                }
            }
    
            #endregion Player Property
    
            private ObservableCollection<Event> _events = new ObservableCollection<Event>();
            public ObservableCollection<Event> Events
            {
                get { return _events; }
                private set
                {
                    if (value != _events)
                    {
                        _events = value;
                        OnPropertyChanged(nameof(Events));
                    }
                }
            }
    
            #region Event Methods
            //  This is a BIG guess as to what you're trying to do.
            public void AddGreeting()
            {
                //  Player is "in scope" because Player is a property of this class. 
                if (Player == null)
                {
                    throw new Exception("Player is null. You can't greet a player who's not there.");
                }
                Events.Add(new Event("\"Greetings {0}. What can I do for you today?\"", Player));
            }
            #endregion Event Methods
        }
    
        public class Employee : ViewModelBase
        {
            #region DisplayLtdOccupationId Property
            private bool _displayLtdOccupationId = default(bool);
            public bool DisplayLtdOccupationId
            {
                get { return _displayLtdOccupationId; }
                set
                {
                    if (value != _displayLtdOccupationId)
                    {
                        _displayLtdOccupationId = value;
                        OnPropertyChanged(nameof(DisplayLtdOccupationId));
                    }
                }
            }
            #endregion DisplayLtdOccupationId Property
        }
    
        public class Event : ViewModelBase
        {
            public Event(String format, PlayerViewModel player)
            {
                _format = format;
                Player = player;
            }
            private String _format = "";
    
            public String Message
            {
                get { return String.Format(_format, Player.Name); }
            }
    
            #region Player Property
            private PlayerViewModel _player = default(PlayerViewModel);
            public PlayerViewModel Player
            {
                get { return _player; }
                set
                {
                    if (value != _player)
                    {
                        _player = value;
                        OnPropertyChanged(nameof(Player));
                        //  When player changes, his name changes, so that 
                        //  means the value of Message will change. 
                        OnPropertyChanged(nameof(Message));
                        if (_player != null)
                        {
                            _player.PropertyChanged += _player_PropertyChanged;
                        }
                    }
                }
            }
    
            private void _player_PropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                switch (e.PropertyName)
                {
                    case nameof(PlayerViewModel.Name):
                        OnPropertyChanged(nameof(Message));
                        break;
                }
            }
            #endregion Player Property
        }
    
        public class PlayerViewModel : ViewModelBase
        {
            private String _name = default(String);
            public String Name
            {
                get { return _name; }
                set
                {
                    if (value != _name)
                    {
                        _name = value;
                        OnPropertyChanged(nameof(Name));
                    }
                }
            }
        }
    }
    

    MainWindow.xaml.cs

    using System.Windows;
    
    namespace Player
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
    
                ViewModel = new MainViewModel();
    
                ViewModel.Player = new PlayerViewModel() { Name = "Ivan the Terrible" };
            }
    
            //  Just here as a convenience, and to make sure we don't give the DataContext
            //  the wrong kind of viewmodel. 
            public MainViewModel ViewModel
            {
                set { DataContext = value; }
                get { return DataContext as MainViewModel; }
            }
    
            private void Greeting_Click(object sender, RoutedEventArgs e)
            {
                ViewModel.AddGreeting();
            }
        }
    }
    

    MainWindow.xaml

    <Window 
        x:Class="Player.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Player"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
        <Grid>
            <StackPanel Orientation="Vertical">
                <WrapPanel>
                    <Button x:Name="Greeting" Content="Greeting" Click="Greeting_Click" />
                    <Label>Name: </Label>
                    <TextBox Text="{Binding Player.Name}" Width="120" />
                </WrapPanel>
                <ListBox
                    ItemsSource="{Binding Events}"
                    DisplayMemberPath="Message"
                    >
                </ListBox>
            </StackPanel>
        </Grid>
    </Window>
    

    【讨论】:

    • 感谢您为此浪费时间,这实际上是在浪费时间。老实说,我有一个大脑汤,试图了解这段代码的整个想法。但我想用代码告诉你我的意图会更容易,所以你会更容易向我解释这一点。我想要做的是创建一个使用玩家姓名而不是 {0} 的“事件”。事件本身显示在文本框中,该文本框通过按下按钮显示特定事件。我的问题是 Player 类和“contentControl”类都存在于同一个类中,并且无法从 MainWindow 类访问对象实例。
    • ...如果它没有让我的意图明确,请务必提及,因为我几乎不适合所有这些。我在最后那段时间真的达到了 0 个字符
    • @Zephylir 您遇到了问题,因为代码组织完全错误。就像你在告诉我问题是你的车不会直上悬崖。这不是真正的问题。问题是你应该在环绕山的路上。
    • @Zephylir 我的版本非常简单——我认为比你的版本更简单。视图模型中的属性有很多东西,但它们都只是 INotifyPropertyChanged 的​​按数字绘制的填充物。你在其他类中定义的所有类都有这个东西,这是没有意义的。我认为您还没有掌握 C# 中有哪些类以及如何使用它们。我想不出比向您展示如何正确地进行解释更快的方法了。我知道学习曲线是 PITA,没有办法。
    • 是的,我明白了,但我就是想不出更好的方法来做到这一点。我可以创建一个“第三方方法”来获取名称和所有内容,但问题是:更改“播放器”的对象实例是否实际上更改了创建它的类?如果不是,那么我需要找到一种从 Player 对象中获取值的方法,因为它的 Name 值是使用“Player.Name = inputBox.Text;”更改的老实说,我认为我的问题完全是错误的。
    【解决方案4】:

    你可以将Nameset改成private,但仍然允许外界通过get读取属性。

    public string Name { get; private set; } = "Default";
    

    这应该为您提供所需的功能,而无需创建新的GetName() 方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-08
      • 1970-01-01
      • 1970-01-01
      • 2013-11-12
      • 2012-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多