programing

WPF/Silverlight 페이지 내의 커스텀 속성 설정

fastcode 2023. 4. 15. 09:34
반응형

WPF/Silverlight 페이지 내의 커스텀 속성 설정

간단해야 할 것처럼 들리네요.는 나나 a a a가 있다PageXAML」( 「XAML 속성.") 및 커스텀 속성이 있습니다.페이지와 관련된 XAML에서 해당 속성을 설정하고 싶습니다.

다른 속성을 설정했을 때와 같은 방법으로 이 작업을 수행하려고 하면 이해는 하지만 어떻게 대처해야 할지 모르기 때문에 작동하지 않습니다.구체적으로는 XAML에 대해 말씀드리겠습니다.원래는 디자이너 사이즈 등의 특성이 있었지만, 이것과는 무관하다고 생각합니다.

<Page x:Class="WpfSandbox.TestPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      MyProperty="MyPropertyValue">
</Page>

및 대응하는 코드 배후에 있습니다.

using System.Windows.Controls;

namespace WpfSandbox {
  public partial class TestPage : Page {
    public TestPage() {
      InitializeComponent();
    }

    public string MyProperty { get; set; }
  }
}

오류 메시지:

오류 1 'MyProperty' 속성이 XML 네임스페이스 'http://schemas.microsoft.com/winfx/2006/xaml/presentation''에 없습니다.라인 4 위치 7

이제 이 문제가 발생하는 이유를 알 수 있습니다. 요소가 유형입니다.Page , , , , 입니다.PageMyProperty은 오직 .TestPage에됩니다.에 의해 지정됩니다.x:Class아트리뷰트, 아트리뷰트, 아트리뷰트, 아트리뷰트XAML의 Visual Studio의 Visual Studio입니다.

의존 재산으로 이 일을 처리할 수 있을 것 같은데, 그건 좀 과잉 살상으로 느껴져요.기존 자산을 사용할 수도 있습니다(예:DataContext나중에 코드 내의 커스텀속성에 값을 카피합니다만, 이것은 매우 보기 흉합니다.

위는 WPF의 예이지만, Silverlight에서도 같은 답변이 적용될 것으로 생각합니다.저는 둘 다 관심이 있습니다.그러니까 한쪽에서는 효과가 있지만 다른 쪽에서는 효과가 없는 답변을 투고해 주시면 감사하겠습니다.

누군가 아주 사소한 해결책을 올리면 난 자책할 준비를 하고 있어

페이지에 대한 기본 클래스를 만드는 경우 종속성 속성 없이 일반 속성으로 작업할 수 있습니다.

public class BaseWindow : Window
{
   public string MyProperty { get; set; }
}
<local:BaseWindow x:Class="BaseWindowSample.Window1" x:Name="winImp"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:BaseWindowSample" 
    MyProperty="myproperty value"
    Title="Window1" Height="300" Width="300">

</local:BaseWindow>

My Property가 종속성이나 첨부 파일이 아닌 경우에도 작동합니다.

Pavel이 지적한 처럼 첨부 가능한 속성으로 만들어야 합니다.그러면 다음과 같은 것을 쓸 수 있습니다.

<Page x:Class="JonSkeetTest.SkeetPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:JonSkeetTest="clr-namespace:JonSkeetTest" mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"
       JonSkeetTest:SkeetPage.MyProperty="testar"
    Title="SkeetPage">
    <Grid>
        
    </Grid>
</Page>

다만, 다음의 코드 배후에 있는 것만으로, 대신에, 에러가 표시됩니다.

연결 가능한 속성 'MyProperty'가 유형 'SkeeetPage'에 없습니다.

연결된 속성 'SkeetPage'입니다.MyProperty'가 'Page' 또는 해당 기본 클래스 중 하나에 정의되어 있지 않습니다.


편집

안타깝게도 종속성 속성을 사용해야 합니다.여기 작업 예가 있습니다.

페이지입니다.

<Page x:Class="JonSkeetTest.SkeetPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:JonSkeetTest="clr-namespace:JonSkeetTest" mc:Ignorable="d" 
      JonSkeetTest:SkeetPage.MyProperty="Testing.."
      d:DesignHeight="300" d:DesignWidth="300"
    Title="SkeetPage">
   
    <Grid>
        <Button Click="ButtonTest_Pressed"></Button>
    </Grid>
</Page>

코드 비하인드

using System.Windows;
using System.Windows.Controls;

namespace JonSkeetTest
{
    public partial class SkeetPage
    {
        public SkeetPage()
        {
            InitializeComponent();
        }

        public static readonly DependencyProperty MyPropertyProperty = DependencyProperty.Register(
          "MyProperty",
          typeof(string),
          typeof(Page),
          new FrameworkPropertyMetadata(null,
              FrameworkPropertyMetadataOptions.AffectsRender
          )
        );

        public static void SetMyProperty(UIElement element, string value)
        {
            element.SetValue(MyPropertyProperty, value);
        }
        public static string GetMyProperty(UIElement element)
        {
            return element.GetValue(MyPropertyProperty).ToString();
        }

        public string MyProperty
        {
            get { return GetValue(MyPropertyProperty).ToString(); }
            set { SetValue(MyPropertyProperty, value); }
        }

        private void ButtonTest_Pressed(object sender, RoutedEventArgs e)
        {
            MessageBox.Show(MyProperty);
        }
    }
}

버튼을 누르면 "테스트 중..."을 클릭합니다.

을 하시면 .<Page>가 것<TestPage>신신: :

<YourApp:TestPage 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
  xmlns:YourApp="clr-namespace:YourApp"
  MyProperty="Hello">
</YourApp:TestPage>

하면, 져 .InitializeComponent()★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★디자인 모드는 아직 흠잡을 데 없이 작동하는 것 같습니다만, 저는 이것을 광범위하게 테스트해 본 적이 없습니다.

업데이트: 컴파일 및 실행되지만 실제로 설정되지는 않습니다.MyProperty또한 XAML에서 이벤트핸들러를 바인드할 수 없게 됩니다(다만, 제가 모르는 이벤트핸들러를 복원할 수 있는 방법이 있을 수도 있습니다).

업데이트 2: 속성을 설정하지만 XAML의 바인딩 이벤트 핸들러는 지원하지 않는 @Fredrik Mörk의 작업 샘플:

코드 비하인드:

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        protected override void OnActivated(EventArgs e)
        {
            this.Title = MyProperty;
        }      

        public string MyProperty { get; set; }
    }
}

XAML:

<WpfApplication1:MainWindow
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:WpfApplication1="clr-namespace:WpfApplication1" 
    Title="MainWindow" 
    Height="350" 
    Width="525"
    MyProperty="My Property Value"> 
</WpfApplication1:MainWindow>

XAML은 다음과 같습니다.

<Page x:Class="SkeetProblem.TestPage"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.MyProperty>MyPropertyValue</Page.MyProperty> 
</Page>

이것은 명백한 불법이다.응용 프로그램클래스의 정적 Load Component 메서드에 의해 XAML 파일이 로드되고 있으며 참조에는 다음과 같이 기재되어 있습니다.

지정된 Uniform Resource Identifier(URI; 유니폼자원 식별자)에 있는 XAML 파일을 로드하여 XAML 파일의 루트 요소에 의해 지정된 개체의 인스턴스로 변환합니다.

즉, 루트 요소로 지정된 유형의 속성만 설정할 수 있습니다.따라서 페이지의 서브클래스를 지정하고 해당 서브클래스를 XAML의 루트 요소로 지정해야 합니다.

이건 내게 효과가 있었다.

<Window x:Class="WpfSandbox.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfSandbox"        
    xmlns:src="clr-namespace:WpfSandbox" 
    Title="MainWindow" Height="350" Width="525"
    src:MainWindow.SuperClick="SuperClickEventHandler">
</Window>

따라서 이 방법은 원래 질문(시도하지 않음)에 적용될 수 있습니다.주 xmlns: src.

<Page x:Class="WpfSandbox.TestPage"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:local="clr-namespace:WpfSandbox"        
  xmlns:src="clr-namespace:WpfSandbox" 
  src:TestPage.MyProperty="MyPropertyValue">
</Page>

Silverlight와 관련된 질문입니다.

당신이 원하는 방식으로 일반 부동산을 사용하는 단순하고 명백한 방법은 없습니다. 그 과정에서 타협이 있을 것입니다.

실제로 동작하지 않는다:-

일부에서는 종속 속성을 제안합니다.그건 안 돼요. 아직 Xaml POV의 공공 재산이에요.연결된 속성은 작동하지만 코드 내에서 해당 속성을 사용하는 것이 좋지 않습니다.

가깝지만 바나나는 없다:-

Xaml과 클래스는 다음과 같이 완전히 분리할 수 있습니다.

<local:PageWithProperty
           xmlns:local="clr-namespace:StackoverflowSpikes"
           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
           xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
    Message="Hello World"
    Loaded="PageWithProperty_Loaded"
    Title="Some Title"
           >
    <Grid x:Name="LayoutRoot">
        <TextBlock Text="{Binding Parent.Message, ElementName=LayoutRoot}" />
    </Grid>
</local:PageWithProperty>

코드:-

public class PageWithProperty : Page
{

        internal System.Windows.Controls.Grid LayoutRoot;

        private bool _contentLoaded;

        public void InitializeComponent()
        {
            if (_contentLoaded) {
                return;
            }
            _contentLoaded = true;
            System.Windows.Application.LoadComponent(this, new System.Uri("/StackoverflowSpikes;component/PageWithProperty.xaml", System.UriKind.Relative));
            this.LayoutRoot = ((System.Windows.Controls.Grid)(this.FindName("LayoutRoot")));
         }

    public PageWithProperty()
    {
        InitializeComponent();
    }

    void PageWithProperty_Loaded(object sender, RoutedEventArgs e)
    {
        MessageBox.Show("Hi");
    }
    public string Message {get; set; }

}

그러나 디자이너의 지원을 일부 잃게 됩니다. 이름 를 보유하기 위한 .InitialiseComponent(IMO가 명명된 항목에 대해 이 모든 자동 필드를 사용하는 것이 반드시 좋은 것은 아닙니다).또한 디자이너는 이벤트 코드를 동적으로 만들지 않지만(이상하게도 수동으로 만든 이벤트 코드를 탐색하는 방법을 알고 있는 것 같습니다), Xaml에서 정의된 이벤트는 런타임에 연결됩니다.

IMO 최적 옵션:-

아비섹이 최선의 타협안을 이미 게시했습니다. 속성을 보유하려면 심 베이스 클래스를 사용하십시오.최소한의 노력과 최대한의 호환성.

제가 제안하는 것은DependencyProperty디폴트 설정:

    public int MyProperty
    {
        get { return (int)GetValue(MyPropertyProperty); }
        set { SetValue(MyPropertyProperty, value); }
    }

    public static readonly DependencyProperty MyPropertyProperty =
        DependencyProperty.Register("MyProperty", typeof(int), typeof(MyClass), 
               new PropertyMetadata(1337)); //<-- Default goes here

컨트롤의 속성을 사용하기 위해 외부에 노출하는 것으로 봅니다.

자신의 자산을 사용하고 싶다면 다음 중 하나를 사용할 수 있습니다.ElementName또는RelativeSource바인딩.

과잉 살상 사건에 대해서요DependencyProperties와 손을 잡다DependencyObjects;)

XAML은 더 이상 필요하지 않습니다.기본값은PropertyMetadata나머진 다 할 거야

정말로 XAML에 삽입하고 싶은 경우는, 베이스 클래스의 솔루션을 선택해 주세요.그렇지 않으면, 다른 컨트롤에서도 사용할 수 있는 접속 가능한 속성을 도입해 주세요.

하지만 다른 의도로 같은 일을 하려고 했을 뿐이에요

실제로는 Set-methods의 WPF 표기법을 올바르게 실시할 필요가 있습니다.http://msdn.microsoft.com/en-us/library/ms749011.aspx#custom 에서 Xxx라는 이름의 첨부 속성을 정의하려면 SetXx 메서드와 GetXx 메서드를 정의해야 합니다.

다음 작업 예를 참조하십시오.

public class Lokalisierer : DependencyObject
{
    public Lokalisierer()
    {
    }

    public static readonly DependencyProperty LIdProperty = 
        DependencyProperty.RegisterAttached("LId", 
                                            typeof(string), 
                                            typeof(Lokalisierer),
                                            new FrameworkPropertyMetadata( 
                                                  null,
                                                     FrameworkPropertyMetadataOptions.AffectsRender | 
                                                     FrameworkPropertyMetadataOptions.AffectsMeasure,
                                                     new PropertyChangedCallback(OnLocIdChanged)));

    private static void OnLocIdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
    // on startup youll be called here
    }

    public static void SetLId(UIElement element, string value)
    {
      element.SetValue(LIdProperty, value);
    }
    public static string GetLId(UIElement element)
    {
      return (string)element.GetValue(LIdProperty);
    }


    public string LId
    {
        get{    return (string)GetValue(LIdProperty);   }
        set{ SetValue(LIdProperty, value); }
    }
}

WPF 부분은 다음과 같습니다.

<Window x:Class="LokalisierungMitAP.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:me="clr-namespace:LokalisierungMitAP"
Title="LokalisierungMitAP" Height="300" Width="300"
>
<StackPanel>
    <Label  me:Lokalisierer.LId="hhh">Label1</Label>
   </StackPanel>

BTW: Dependency Object도 상속해야 합니다.

이렇게 액세스하려면 연결 가능한 속성으로 정의해야 합니다.

스타일을 사용하여 속성을 설정할 수 있습니다.

<Page.Style>
    <Style TargetType="{x:Type wpfSandbox:TestPage}">
        <Setter Property="MyProperty" Value="This works" />
    </Style>
</Page.Style>

그러나 종속성 속성에 대해서만 작동합니다.

public static readonly DependencyProperty MyPropertyProperty = DependencyProperty.Register(
    nameof(MyProperty), typeof(string), typeof(Page),
    new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender));

public string MyProperty
{
    get { return (string)GetValue(MyPropertyProperty); }
    set { SetValue(MyPropertyProperty, value); }
}

언급URL : https://stackoverflow.com/questions/3657778/setting-a-custom-property-within-a-wpf-silverlight-page

반응형