diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index ec2bf49ba..a2346ef1e 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,44 +1,41 @@ -# GitHub Copilot Instructions (WindowsAppSDK-Samples) - -Read scripts first; improve their headers instead of duplicating detail here. - -## Build -Use only `build.ps1` / `build.cmd`. Read `build.ps1` before invoking. It auto: detects platform, picks solutions (current dir > selected sample > all), initializes VS DevShell, restores via local nuget, emits `.binlog` per solution. Do NOT hand-roll msbuild/nuget restore logic. - -## Versions -Run `UpdateVersions.ps1` only after reading it. Get the WinAppSDK version string from: https://www.nuget.org/packages/Microsoft.WindowsAppSdk/ (stable/preview/servicing) and pass as `-WinAppSDKVersion`. - -## Coding Guidelines -- Small, focused diffs; no mass reformatting; ensure SOLID principles. -- Preserve APIs, encoding, line endings, relative paths. -- PowerShell: approved verbs; each new script has Synopsis/Description/Parameters/Examples header. -- C#/C++: follow existing style; lean headers; forward declare where practical; keep samples illustrative. -- Minimal necessary comments; avoid noise. Centralize user strings for localization. -- Never log secrets or absolute external paths. - -## Language style rules -- Always enforce repo analyzers: root `.editorconfig` plus any `stylecop.json`. -- C# code follows StyleCop.Analyzers and Microsoft.CodeAnalysis.NetAnalyzers. -- C++ code honors `.clang-format` plus `.clang-tidy` (modernize/cppcoreguidelines/readability). -- Markdown files wrap at 80 characters and use ATX headers with fenced code blocks that include language tags. -- YAML files indent two spaces and add comments for complex settings while keeping keys clear. -- PowerShell scripts use Verb-Noun names and prefer single-quoted literals while documenting parameters and satisfying PSScriptAnalyzer. - -## PR Guidance -- One intent per PR. Update script README/header if behavior changes. -- Provide summary: what / why / validation. -- Run a targeted build (e.g. `pwsh -File build.ps1 -Sample AppLifecycle`). -- For version bumps: inspect at least one changed project file. -- No new warnings/errors or large cosmetic churn. - -## Design Docs (Large / Cross-Sample) -Before broad edits create `DESIGN-.md`: -- Single sample: `Samples//DESIGN-.md` -- Multi-sample/shared: repo root. -Include: Problem, Goals/Non-Goals, Affected Areas, Approach, Risks, Validation Plan. Reference doc in PR. - -## When Unsure -Draft a design doc or WIP PR summarizing assumptions—don't guess. - --- -Keep this file lean; source-of-truth for behavior lives in script headers. \ No newline at end of file +description: 'Windows App SDK Samples AI contributor guidance' +--- + +# Windows App SDK Samples – Copilot Instructions + +Concise guidance for AI contributions to Windows App SDK Samples. For complete details, see [AGENTS.md](../AGENTS.md). + +## Quick Reference + +- **Build**: `build.ps1` / `build.cmd` (supports `-Sample ` for targeted builds) +- **Run**: Test on x64, x86, ARM64 in Debug and Release +- **Verify**: Run WACK on Release builds +- **Exit code 0 = success** – do not proceed if build fails + +## Key Rules + +- Samples should be **complete but simple** – demonstrate correct API usage +- Follow **scenario-based design** – one scenario per API usage pattern +- Support all platforms: x64, x86, ARM64 (Debug and Release) +- Minimum OS: Windows 10 version 1809 (build 17763) +- Include copyright headers; build clean with no warnings + +## Style Enforcement + +- **C#**: Follow `.editorconfig` at repo root +- **C++**: Use C++/WinRT; check `Samples/WindowsML/` for `.clang-format` + +## When to Ask for Clarification + +- Ambiguous sample requirements after reviewing docs +- Cross-feature impact unclear +- API usage patterns not well documented + +## Detailed Documentation + +- [AGENTS.md](../AGENTS.md) – Full AI contributor guide +- [Samples Guidelines](../docs/samples-guidelines.md) – Complete guidelines and checklist +- [Contributing](../CONTRIBUTING.md) – Contribution requirements +- [PR Template](../docs/pull_request_template.md) – Pull request checklist +- [Windows App SDK Docs](https://docs.microsoft.com/windows/apps/windows-app-sdk/) – Official documentation diff --git a/.github/instructions/agents.instructions.md b/.github/instructions/agents.instructions.md new file mode 100644 index 000000000..8d602c881 --- /dev/null +++ b/.github/instructions/agents.instructions.md @@ -0,0 +1,791 @@ +--- +description: 'Guidelines for creating custom agent files for GitHub Copilot' +applyTo: '**/*.agent.md' +--- + +# Custom Agent File Guidelines + +Instructions for creating effective and maintainable custom agent files that provide specialized expertise for specific development tasks in GitHub Copilot. + +## Project Context + +- Target audience: Developers creating custom agents for GitHub Copilot +- File format: Markdown with YAML frontmatter +- File naming convention: lowercase with hyphens (e.g., `test-specialist.agent.md`) +- Location: `.github/agents/` directory (repository-level) or `agents/` directory (organization/enterprise-level) +- Purpose: Define specialized agents with tailored expertise, tools, and instructions for specific tasks +- Official documentation: https://docs.github.com/en/copilot/how-tos/use-copilot-agents/coding-agent/create-custom-agents + +## Required Frontmatter + +Every agent file must include YAML frontmatter with the following fields: + +```yaml +--- +description: 'Brief description of the agent purpose and capabilities' +name: 'Agent Display Name' +tools: ['read', 'edit', 'search'] +model: 'Claude Sonnet 4.5' +target: 'vscode' +infer: true +--- +``` + +### Core Frontmatter Properties + +#### **description** (REQUIRED) +- Single-quoted string, clearly stating the agent's purpose and domain expertise +- Should be concise (50-150 characters) and actionable +- Example: `'Focuses on test coverage, quality, and testing best practices'` + +#### **name** (OPTIONAL) +- Display name for the agent in the UI +- If omitted, defaults to filename (without `.md` or `.agent.md`) +- Use title case and be descriptive +- Example: `'Testing Specialist'` + +#### **tools** (OPTIONAL) +- List of tool names or aliases the agent can use +- Supports comma-separated string or YAML array format +- If omitted, agent has access to all available tools +- See "Tool Configuration" section below for details + +#### **model** (STRONGLY RECOMMENDED) +- Specifies which AI model the agent should use +- Supported in VS Code, JetBrains IDEs, Eclipse, and Xcode +- Example: `'Claude Sonnet 4.5'`, `'gpt-4'`, `'gpt-4o'` +- Choose based on agent complexity and required capabilities + +#### **target** (OPTIONAL) +- Specifies target environment: `'vscode'` or `'github-copilot'` +- If omitted, agent is available in both environments +- Use when agent has environment-specific features + +#### **infer** (OPTIONAL) +- Boolean controlling whether Copilot can automatically use this agent based on context +- Default: `true` if omitted +- Set to `false` to require manual agent selection + +#### **metadata** (OPTIONAL, GitHub.com only) +- Object with name-value pairs for agent annotation +- Example: `metadata: { category: 'testing', version: '1.0' }` +- Not supported in VS Code + +#### **mcp-servers** (OPTIONAL, Organization/Enterprise only) +- Configure MCP servers available only to this agent +- Only supported for organization/enterprise level agents +- See "MCP Server Configuration" section below + +## Tool Configuration + +### Tool Specification Strategies + +**Enable all tools** (default): +```yaml +# Omit tools property entirely, or use: +tools: ['*'] +``` + +**Enable specific tools**: +```yaml +tools: ['read', 'edit', 'search', 'execute'] +``` + +**Enable MCP server tools**: +```yaml +tools: ['read', 'edit', 'github/*', 'playwright/navigate'] +``` + +**Disable all tools**: +```yaml +tools: [] +``` + +### Standard Tool Aliases + +All aliases are case-insensitive: + +| Alias | Alternative Names | Category | Description | +|-------|------------------|----------|-------------| +| `execute` | shell, Bash, powershell | Shell execution | Execute commands in appropriate shell | +| `read` | Read, NotebookRead, view | File reading | Read file contents | +| `edit` | Edit, MultiEdit, Write, NotebookEdit | File editing | Edit and modify files | +| `search` | Grep, Glob, search | Code search | Search for files or text in files | +| `agent` | custom-agent, Task | Agent invocation | Invoke other custom agents | +| `web` | WebSearch, WebFetch | Web access | Fetch web content and search | +| `todo` | TodoWrite | Task management | Create and manage task lists (VS Code only) | + +### Built-in MCP Server Tools + +**GitHub MCP Server**: +```yaml +tools: ['github/*'] # All GitHub tools +tools: ['github/get_file_contents', 'github/search_repositories'] # Specific tools +``` +- All read-only tools available by default +- Token scoped to source repository + +**Playwright MCP Server**: +```yaml +tools: ['playwright/*'] # All Playwright tools +tools: ['playwright/navigate', 'playwright/screenshot'] # Specific tools +``` +- Configured to access localhost only +- Useful for browser automation and testing + +### Tool Selection Best Practices + +- **Principle of Least Privilege**: Only enable tools necessary for the agent's purpose +- **Security**: Limit `execute` access unless explicitly required +- **Focus**: Fewer tools = clearer agent purpose and better performance +- **Documentation**: Comment why specific tools are required for complex configurations + +## Sub-Agent Invocation (Agent Orchestration) + +Agents can invoke other agents using `runSubagent` to orchestrate multi-step workflows. + +### How It Works + +Include `agent` in tools list to enable sub-agent invocation: + +```yaml +tools: ['read', 'edit', 'search', 'agent'] +``` + +Then invoke other agents with `runSubagent`: + +```javascript +const result = await runSubagent({ + description: 'What this step does', + prompt: `You are the [Specialist] specialist. + +Context: +- Parameter: ${parameterValue} +- Input: ${inputPath} +- Output: ${outputPath} + +Task: +1. Do the specific work +2. Write results to output location +3. Return summary of completion` +}); +``` + +### Basic Pattern + +Structure each sub-agent call with: + +1. **description**: Clear one-line purpose of the sub-agent invocation +2. **prompt**: Detailed instructions with substituted variables + +The prompt should include: +- Who the sub-agent is (specialist role) +- What context it needs (parameters, paths) +- What to do (concrete tasks) +- Where to write output +- What to return (summary) + +### Example: Multi-Step Processing + +```javascript +// Step 1: Process data +const processing = await runSubagent({ + description: 'Transform raw input data', + prompt: `You are the Data Processor specialist. + +Project: ${projectName} +Input: ${basePath}/raw/ +Output: ${basePath}/processed/ + +Task: +1. Read all files from input directory +2. Apply transformations +3. Write processed files to output +4. Create summary: ${basePath}/processed/summary.md + +Return: Number of files processed and any issues found` +}); + +// Step 2: Analyze (depends on Step 1) +const analysis = await runSubagent({ + description: 'Analyze processed data', + prompt: `You are the Data Analyst specialist. + +Project: ${projectName} +Input: ${basePath}/processed/ +Output: ${basePath}/analysis/ + +Task: +1. Read processed files from input +2. Generate analysis report +3. Write to: ${basePath}/analysis/report.md + +Return: Key findings and identified patterns` +}); +``` + +### Key Points + +- **Pass variables in prompts**: Use `${variableName}` for all dynamic values +- **Keep prompts focused**: Clear, specific tasks for each sub-agent +- **Return summaries**: Each sub-agent should report what it accomplished +- **Sequential execution**: Use `await` to maintain order when steps depend on each other +- **Error handling**: Check results before proceeding to dependent steps + +### ⚠️ Tool Availability Requirement + +**Critical**: If a sub-agent requires specific tools (e.g., `edit`, `execute`, `search`), the orchestrator must include those tools in its own `tools` list. Sub-agents cannot access tools that aren't available to their parent orchestrator. + +**Example**: +```yaml +# If your sub-agents need to edit files, execute commands, or search code +tools: ['read', 'edit', 'search', 'execute', 'agent'] +``` + +The orchestrator's tool permissions act as a ceiling for all invoked sub-agents. Plan your tool list carefully to ensure all sub-agents have the tools they need. + +### ⚠️ Important Limitation + +**Sub-agent orchestration is NOT suitable for large-scale data processing.** Avoid using `runSubagent` when: +- Processing hundreds or thousands of files +- Handling large datasets +- Performing bulk transformations on big codebases +- Orchestrating more than 5-10 sequential steps + +Each sub-agent call adds latency and context overhead. For high-volume processing, implement logic directly in a single agent instead. Use orchestration only for coordinating specialized tasks on focused, manageable datasets. + +## Agent Prompt Structure + +The markdown content below the frontmatter defines the agent's behavior, expertise, and instructions. Well-structured prompts typically include: + +1. **Agent Identity and Role**: Who the agent is and its primary role +2. **Core Responsibilities**: What specific tasks the agent performs +3. **Approach and Methodology**: How the agent works to accomplish tasks +4. **Guidelines and Constraints**: What to do/avoid and quality standards +5. **Output Expectations**: Expected output format and quality + +### Prompt Writing Best Practices + +- **Be Specific and Direct**: Use imperative mood ("Analyze", "Generate"); avoid vague terms +- **Define Boundaries**: Clearly state scope limits and constraints +- **Include Context**: Explain domain expertise and reference relevant frameworks +- **Focus on Behavior**: Describe how the agent should think and work +- **Use Structured Format**: Headers, bullets, and lists make prompts scannable + +## Variable Definition and Extraction + +Agents can define dynamic parameters to extract values from user input and use them throughout the agent's behavior and sub-agent communications. This enables flexible, context-aware agents that adapt to user-provided data. + +### When to Use Variables + +**Use variables when**: +- Agent behavior depends on user input +- Need to pass dynamic values to sub-agents +- Want to make agents reusable across different contexts +- Require parameterized workflows +- Need to track or reference user-provided context + +**Examples**: +- Extract project name from user prompt +- Capture certification name for pipeline processing +- Identify file paths or directories +- Extract configuration options +- Parse feature names or module identifiers + +### Variable Declaration Pattern + +Define variables section early in the agent prompt to document expected parameters: + +```markdown +# Agent Name + +## Dynamic Parameters + +- **Parameter Name**: Description and usage +- **Another Parameter**: How it's extracted and used + +## Your Mission + +Process [PARAMETER_NAME] to accomplish [task]. +``` + +### Variable Extraction Methods + +#### 1. **Explicit User Input** +Ask the user to provide the variable if not detected in the prompt: + +```markdown +## Your Mission + +Process the project by analyzing your codebase. + +### Step 1: Identify Project +If no project name is provided, **ASK THE USER** for: +- Project name or identifier +- Base path or directory location +- Configuration type (if applicable) + +Use this information to contextualize all subsequent tasks. +``` + +#### 2. **Implicit Extraction from Prompt** +Automatically extract variables from the user's natural language input: + +```javascript +// Example: Extract certification name from user input +const userInput = "Process My Certification"; + +// Extract key information +const certificationName = extractCertificationName(userInput); +// Result: "My Certification" + +const basePath = `certifications/${certificationName}`; +// Result: "certifications/My Certification" +``` + +#### 3. **Contextual Variable Resolution** +Use file context or workspace information to derive variables: + +```markdown +## Variable Resolution Strategy + +1. **From User Prompt**: First, look for explicit mentions in user input +2. **From File Context**: Check current file name or path +3. **From Workspace**: Use workspace folder or active project +4. **From Settings**: Reference configuration files +5. **Ask User**: If all else fails, request missing information +``` + +### Using Variables in Agent Prompts + +#### Variable Substitution in Instructions + +Use template variables in agent prompts to make them dynamic: + +```markdown +# Agent Name + +## Dynamic Parameters +- **Project Name**: ${projectName} +- **Base Path**: ${basePath} +- **Output Directory**: ${outputDir} + +## Your Mission + +Process the **${projectName}** project located at `${basePath}`. + +## Process Steps + +1. Read input from: `${basePath}/input/` +2. Process files according to project configuration +3. Write results to: `${outputDir}/` +4. Generate summary report + +## Quality Standards + +- Maintain project-specific coding standards for **${projectName}** +- Follow directory structure: `${basePath}/[structure]` +``` + +#### Passing Variables to Sub-Agents + +When invoking a sub-agent, pass all context through template variables in the prompt: + +```javascript +// Extract and prepare variables +const basePath = `projects/${projectName}`; +const inputPath = `${basePath}/src/`; +const outputPath = `${basePath}/docs/`; + +// Pass to sub-agent with all variables substituted +const result = await runSubagent({ + description: 'Generate project documentation', + prompt: `You are the Documentation specialist. + +Project: ${projectName} +Input: ${inputPath} +Output: ${outputPath} + +Task: +1. Read source files from ${inputPath} +2. Generate comprehensive documentation +3. Write to ${outputPath}/index.md +4. Include code examples and usage guides + +Return: Summary of documentation generated (file count, word count)` +}); +``` + +The sub-agent receives all necessary context embedded in the prompt. Variables are resolved before sending the prompt, so the sub-agent works with concrete paths and values, not variable placeholders. + +### Real-World Example: Code Review Orchestrator + +Example of a simple orchestrator that validates code through multiple specialized agents: + +```javascript +async function reviewCodePipeline(repositoryName, prNumber) { + const basePath = `projects/${repositoryName}/pr-${prNumber}`; + + // Step 1: Security Review + const security = await runSubagent({ + description: 'Scan for security vulnerabilities', + prompt: `You are the Security Reviewer specialist. + +Repository: ${repositoryName} +PR: ${prNumber} +Code: ${basePath}/changes/ + +Task: +1. Scan code for OWASP Top 10 vulnerabilities +2. Check for injection attacks, auth flaws +3. Write findings to ${basePath}/security-review.md + +Return: List of critical, high, and medium issues found` + }); + + // Step 2: Test Coverage Check + const coverage = await runSubagent({ + description: 'Verify test coverage for changes', + prompt: `You are the Test Coverage specialist. + +Repository: ${repositoryName} +PR: ${prNumber} +Changes: ${basePath}/changes/ + +Task: +1. Analyze code coverage for modified files +2. Identify untested critical paths +3. Write report to ${basePath}/coverage-report.md + +Return: Current coverage percentage and gaps` + }); + + // Step 3: Aggregate Results + const finalReport = await runSubagent({ + description: 'Compile all review findings', + prompt: `You are the Review Aggregator specialist. + +Repository: ${repositoryName} +Reports: ${basePath}/*.md + +Task: +1. Read all review reports from ${basePath}/ +2. Synthesize findings into single report +3. Determine overall verdict (APPROVE/NEEDS_FIXES/BLOCK) +4. Write to ${basePath}/final-review.md + +Return: Final verdict and executive summary` + }); + + return finalReport; +} +``` + +This pattern applies to any orchestration scenario: extract variables, call sub-agents with clear context, await results. + + +### Variable Best Practices + +#### 1. **Clear Documentation** +Always document what variables are expected: + +```markdown +## Required Variables +- **projectName**: The name of the project (string, required) +- **basePath**: Root directory for project files (path, required) + +## Optional Variables +- **mode**: Processing mode - quick/standard/detailed (enum, default: standard) +- **outputFormat**: Output format - markdown/json/html (enum, default: markdown) + +## Derived Variables +- **outputDir**: Automatically set to ${basePath}/output +- **logFile**: Automatically set to ${basePath}/.log.md +``` + +#### 2. **Consistent Naming** +Use consistent variable naming conventions: + +```javascript +// Good: Clear, descriptive naming +const variables = { + projectName, // What project to work on + basePath, // Where project files are located + outputDirectory, // Where to save results + processingMode, // How to process (detail level) + configurationPath // Where config files are +}; + +// Avoid: Ambiguous or inconsistent +const bad_variables = { + name, // Too generic + path, // Unclear which path + mode, // Too short + config // Too vague +}; +``` + +#### 3. **Validation and Constraints** +Document valid values and constraints: + +```markdown +## Variable Constraints + +**projectName**: +- Type: string (alphanumeric, hyphens, underscores allowed) +- Length: 1-100 characters +- Required: yes +- Pattern: `/^[a-zA-Z0-9_-]+$/` + +**processingMode**: +- Type: enum +- Valid values: "quick" (< 5min), "standard" (5-15min), "detailed" (15+ min) +- Default: "standard" +- Required: no +``` + +## MCP Server Configuration (Organization/Enterprise Only) + +MCP servers extend agent capabilities with additional tools. Only supported for organization and enterprise-level agents. + +### Configuration Format + +```yaml +--- +name: my-custom-agent +description: 'Agent with MCP integration' +tools: ['read', 'edit', 'custom-mcp/tool-1'] +mcp-servers: + custom-mcp: + type: 'local' + command: 'some-command' + args: ['--arg1', '--arg2'] + tools: ["*"] + env: + ENV_VAR_NAME: ${{ secrets.API_KEY }} +--- +``` + +### MCP Server Properties + +- **type**: Server type (`'local'` or `'stdio'`) +- **command**: Command to start the MCP server +- **args**: Array of command arguments +- **tools**: Tools to enable from this server (`["*"]` for all) +- **env**: Environment variables (supports secrets) + +### Environment Variables and Secrets + +Secrets must be configured in repository settings under "copilot" environment. + +**Supported syntax**: +```yaml +env: + # Environment variable only + VAR_NAME: COPILOT_MCP_ENV_VAR_VALUE + + # Variable with header + VAR_NAME: $COPILOT_MCP_ENV_VAR_VALUE + VAR_NAME: ${COPILOT_MCP_ENV_VAR_VALUE} + + # GitHub Actions-style (YAML only) + VAR_NAME: ${{ secrets.COPILOT_MCP_ENV_VAR_VALUE }} + VAR_NAME: ${{ var.COPILOT_MCP_ENV_VAR_VALUE }} +``` + +## File Organization and Naming + +### Repository-Level Agents +- Location: `.github/agents/` +- Scope: Available only in the specific repository +- Access: Uses repository-configured MCP servers + +### Organization/Enterprise-Level Agents +- Location: `.github-private/agents/` (then move to `agents/` root) +- Scope: Available across all repositories in org/enterprise +- Access: Can configure dedicated MCP servers + +### Naming Conventions +- Use lowercase with hyphens: `test-specialist.agent.md` +- Name should reflect agent purpose +- Filename becomes default agent name (if `name` not specified) +- Allowed characters: `.`, `-`, `_`, `a-z`, `A-Z`, `0-9` + +## Agent Processing and Behavior + +### Versioning +- Based on Git commit SHAs for the agent file +- Create branches/tags for different agent versions +- Instantiated using latest version for repository/branch +- PR interactions use same agent version for consistency + +### Name Conflicts +Priority (highest to lowest): +1. Repository-level agent +2. Organization-level agent +3. Enterprise-level agent + +Lower-level configurations override higher-level ones with the same name. + +### Tool Processing +- `tools` list filters available tools (built-in and MCP) +- No tools specified = all tools enabled +- Empty list (`[]`) = all tools disabled +- Specific list = only those tools enabled +- Unrecognized tool names are ignored (allows environment-specific tools) + +### MCP Server Processing Order +1. Out-of-the-box MCP servers (e.g., GitHub MCP) +2. Custom agent MCP configuration (org/enterprise only) +3. Repository-level MCP configurations + +Each level can override settings from previous levels. + +## Agent Creation Checklist + +### Frontmatter +- [ ] `description` field present and descriptive (50-150 chars) +- [ ] `description` wrapped in single quotes +- [ ] `name` specified (optional but recommended) +- [ ] `tools` configured appropriately (or intentionally omitted) +- [ ] `model` specified for optimal performance +- [ ] `target` set if environment-specific +- [ ] `infer` set to `false` if manual selection required + +### Prompt Content +- [ ] Clear agent identity and role defined +- [ ] Core responsibilities listed explicitly +- [ ] Approach and methodology explained +- [ ] Guidelines and constraints specified +- [ ] Output expectations documented +- [ ] Examples provided where helpful +- [ ] Instructions are specific and actionable +- [ ] Scope and boundaries clearly defined +- [ ] Total content under 30,000 characters + +### File Structure +- [ ] Filename follows lowercase-with-hyphens convention +- [ ] File placed in correct directory (`.github/agents/` or `agents/`) +- [ ] Filename uses only allowed characters +- [ ] File extension is `.agent.md` + +### Quality Assurance +- [ ] Agent purpose is unique and not duplicative +- [ ] Tools are minimal and necessary +- [ ] Instructions are clear and unambiguous +- [ ] Agent has been tested with representative tasks +- [ ] Documentation references are current +- [ ] Security considerations addressed (if applicable) + +## Common Agent Patterns + +### Testing Specialist +**Purpose**: Focus on test coverage and quality +**Tools**: All tools (for comprehensive test creation) +**Approach**: Analyze, identify gaps, write tests, avoid production code changes + +### Implementation Planner +**Purpose**: Create detailed technical plans and specifications +**Tools**: Limited to `['read', 'search', 'edit']` +**Approach**: Analyze requirements, create documentation, avoid implementation + +### Code Reviewer +**Purpose**: Review code quality and provide feedback +**Tools**: `['read', 'search']` only +**Approach**: Analyze, suggest improvements, no direct modifications + +### Refactoring Specialist +**Purpose**: Improve code structure and maintainability +**Tools**: `['read', 'search', 'edit']` +**Approach**: Analyze patterns, propose refactorings, implement safely + +### Security Auditor +**Purpose**: Identify security issues and vulnerabilities +**Tools**: `['read', 'search', 'web']` +**Approach**: Scan code, check against OWASP, report findings + +## Common Mistakes to Avoid + +### Frontmatter Errors +- ❌ Missing `description` field +- ❌ Description not wrapped in quotes +- ❌ Invalid tool names without checking documentation +- ❌ Incorrect YAML syntax (indentation, quotes) + +### Tool Configuration Issues +- ❌ Granting excessive tool access unnecessarily +- ❌ Missing required tools for agent's purpose +- ❌ Not using tool aliases consistently +- ❌ Forgetting MCP server namespace (`server-name/tool`) + +### Prompt Content Problems +- ❌ Vague, ambiguous instructions +- ❌ Conflicting or contradictory guidelines +- ❌ Lack of clear scope definition +- ❌ Missing output expectations +- ❌ Overly verbose instructions (exceeding character limits) +- ❌ No examples or context for complex tasks + +### Organizational Issues +- ❌ Filename doesn't reflect agent purpose +- ❌ Wrong directory (confusing repo vs org level) +- ❌ Using spaces or special characters in filename +- ❌ Duplicate agent names causing conflicts + +## Testing and Validation + +### Manual Testing +1. Create the agent file with proper frontmatter +2. Reload VS Code or refresh GitHub.com +3. Select the agent from the dropdown in Copilot Chat +4. Test with representative user queries +5. Verify tool access works as expected +6. Confirm output meets expectations + +### Integration Testing +- Test agent with different file types in scope +- Verify MCP server connectivity (if configured) +- Check agent behavior with missing context +- Test error handling and edge cases +- Validate agent switching and handoffs + +### Quality Checks +- Run through agent creation checklist +- Review against common mistakes list +- Compare with example agents in repository +- Get peer review for complex agents +- Document any special configuration needs + +## Additional Resources + +### Official Documentation +- [Creating Custom Agents](https://docs.github.com/en/copilot/how-tos/use-copilot-agents/coding-agent/create-custom-agents) +- [Custom Agents Configuration](https://docs.github.com/en/copilot/reference/custom-agents-configuration) +- [Custom Agents in VS Code](https://code.visualstudio.com/docs/copilot/customization/custom-agents) +- [MCP Integration](https://docs.github.com/en/copilot/how-tos/use-copilot-agents/coding-agent/extend-coding-agent-with-mcp) + +### Community Resources +- [Awesome Copilot Agents Collection](https://github.com/github/awesome-copilot/tree/main/agents) +- [Customization Library Examples](https://docs.github.com/en/copilot/tutorials/customization-library/custom-agents) +- [Your First Custom Agent Tutorial](https://docs.github.com/en/copilot/tutorials/customization-library/custom-agents/your-first-custom-agent) + +### Related Files +- [Prompt Files Guidelines](./prompt.instructions.md) - For creating prompt files +- [Instructions Guidelines](./instructions.instructions.md) - For creating instruction files + +## Version Compatibility Notes + +### GitHub.com (Coding Agent) +- ✅ Fully supports all standard frontmatter properties +- ✅ Repository and org/enterprise level agents +- ✅ MCP server configuration (org/enterprise) +- ❌ Does not support `model`, `argument-hint`, `handoffs` properties + +### VS Code / JetBrains / Eclipse / Xcode +- ✅ Supports `model` property for AI model selection +- ✅ Supports `argument-hint` and `handoffs` properties +- ✅ User profile and workspace-level agents +- ❌ Cannot configure MCP servers at repository level +- ⚠️ Some properties may behave differently + +When creating agents for multiple environments, focus on common properties and test in all target environments. Use `target` property to create environment-specific agents when necessary. diff --git a/.github/instructions/azure-devops-pipelines.instructions.md b/.github/instructions/azure-devops-pipelines.instructions.md new file mode 100644 index 000000000..de366c0a6 --- /dev/null +++ b/.github/instructions/azure-devops-pipelines.instructions.md @@ -0,0 +1,228 @@ +--- +description: 'Best practices for Azure DevOps Pipeline YAML files' +applyTo: '**/azure-pipelines.yml, **/azure-pipelines*.yml, **/*.pipeline.yml, **/SamplesCI-*.yml, **/WindowsAppSDK-*.yml' +--- + +# Azure DevOps Pipeline YAML Best Practices + +Guidelines for creating maintainable, secure, and efficient Azure DevOps pipelines in WindowsAppSDK-Samples. + +## General Guidelines + +- Use YAML syntax consistently with proper indentation (2 spaces) +- Always include meaningful names and display names for pipelines, stages, jobs, and steps +- Implement proper error handling and conditional execution +- Use variables and parameters to make pipelines reusable and maintainable +- Follow the principle of least privilege for service connections and permissions +- Include comprehensive logging and diagnostics for troubleshooting + +## Pipeline Structure + +- Organize complex pipelines using stages for better visualization and control +- Use jobs to group related steps and enable parallel execution when possible +- Implement proper dependencies between stages and jobs +- Use templates for reusable pipeline components +- Keep pipeline files focused and modular - split large pipelines into multiple files + +## Build Best Practices + +- Use specific agent pool versions and VM images for consistency +- Cache dependencies (npm, NuGet, Maven, etc.) to improve build performance +- Implement proper artifact management with meaningful names and retention policies +- Use build variables for version numbers and build metadata +- Include code quality gates (lint checks, testing, security scans) +- Ensure builds are reproducible and environment-independent + +## Testing Integration + +- Run unit tests as part of the build process +- Publish test results in standard formats (JUnit, VSTest, etc.) +- Include code coverage reporting and quality gates +- Implement integration and end-to-end tests in appropriate stages +- Use test impact analysis when available to optimize test execution +- Fail fast on test failures to provide quick feedback + +## Security Considerations + +- Use Azure Key Vault for sensitive configuration and secrets +- Implement proper secret management with variable groups +- Use service connections with minimal required permissions +- Enable security scans (dependency vulnerabilities, static analysis) +- Implement approval gates for production deployments +- Use managed identities when possible instead of service principals + +## Deployment Strategies + +- Implement proper environment promotion (dev → staging → production) +- Use deployment jobs with proper environment targeting +- Implement blue-green or canary deployment strategies when appropriate +- Include rollback mechanisms and health checks +- Use infrastructure as code (ARM, Bicep, Terraform) for consistent deployments +- Implement proper configuration management per environment + +## Variable and Parameter Management + +- Use variable groups for shared configuration across pipelines +- Implement runtime parameters for flexible pipeline execution +- Use conditional variables based on branches or environments +- Secure sensitive variables and mark them as secrets +- Document variable purposes and expected values +- Use variable templates for complex variable logic + +## Performance Optimization + +- Use parallel jobs and matrix strategies when appropriate +- Implement proper caching strategies for dependencies and build outputs +- Use shallow clone for Git operations when full history isn't needed +- Optimize Docker image builds with multi-stage builds and layer caching +- Monitor pipeline performance and optimize bottlenecks +- Use pipeline resource triggers efficiently + +## Monitoring and Observability + +- Include comprehensive logging throughout the pipeline +- Use Azure Monitor and Application Insights for deployment tracking +- Implement proper notification strategies for failures and successes +- Include deployment health checks and automated rollback triggers +- Use pipeline analytics to identify improvement opportunities +- Document pipeline behavior and troubleshooting steps + +## Template and Reusability + +- Create pipeline templates for common patterns +- Use extends templates for complete pipeline inheritance +- Implement step templates for reusable task sequences +- Use variable templates for complex variable logic +- Version templates appropriately for stability +- Document template parameters and usage examples + +## Branch and Trigger Strategy + +- Implement appropriate triggers for different branch types +- Use path filters to trigger builds only when relevant files change +- Configure proper CI/CD triggers for main/master branches +- Use pull request triggers for code validation +- Implement scheduled triggers for maintenance tasks +- Consider resource triggers for multi-repository scenarios + +## Example Structure + +```yaml +# azure-pipelines.yml +trigger: + branches: + include: + - main + - develop + paths: + exclude: + - docs/* + - README.md + +variables: + - group: shared-variables + - name: buildConfiguration + value: 'Release' + +stages: + - stage: Build + displayName: 'Build and Test' + jobs: + - job: Build + displayName: 'Build Application' + pool: + vmImage: 'ubuntu-latest' + steps: + - task: UseDotNet@2 + displayName: 'Use .NET SDK' + inputs: + version: '8.x' + + - task: DotNetCoreCLI@2 + displayName: 'Restore dependencies' + inputs: + command: 'restore' + projects: '**/*.csproj' + + - task: DotNetCoreCLI@2 + displayName: 'Build application' + inputs: + command: 'build' + projects: '**/*.csproj' + arguments: '--configuration $(buildConfiguration) --no-restore' + + - stage: Deploy + displayName: 'Deploy to Staging' + dependsOn: Build + condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main')) + jobs: + - deployment: DeployToStaging + displayName: 'Deploy to Staging Environment' + environment: 'staging' + strategy: + runOnce: + deploy: + steps: + - download: current + displayName: 'Download drop artifact' + artifact: drop + - task: AzureWebApp@1 + displayName: 'Deploy to Azure Web App' + inputs: + azureSubscription: 'staging-service-connection' + appType: 'webApp' + appName: 'myapp-staging' + package: '$(Pipeline.Workspace)/drop/**/*.zip' +``` + +## Common Anti-Patterns to Avoid + +- Hardcoding sensitive values directly in YAML files +- Using overly broad triggers that cause unnecessary builds +- Mixing build and deployment logic in a single stage +- Not implementing proper error handling and cleanup +- Using deprecated task versions without upgrade plans +- Creating monolithic pipelines that are difficult to maintain +- Not using proper naming conventions for clarity +- Ignoring pipeline security best practices + +## WindowsAppSDK-Samples Specific Patterns + +### Feature-Specific CI Pipelines + +Each feature in the Samples repo should have its own CI pipeline. Create a new pipeline file named `SamplesCI-.yml` at the repository root: + +```yaml +# SamplesCI-.yml +name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr) +stages: +- template: WindowsAppSDK-SamplesCI.yml + parameters: + FeatureDirectory: "" +``` + +### Adding Features to SamplesCI-All.yml + +When onboarding a new feature, add it to the `FeatureAreas` parameter in `SamplesCI-All.yml` to include it in comprehensive builds. + +### Pipeline Setup Requirements + +1. **Triggers**: Configure pull request validation with path filters for your feature directory +2. **Branch Filters**: Include `refs/heads/main` +3. **Path Filters**: Include `Samples/` +4. **Fork Builds**: Enable "Build pull requests from forks of this repository" +5. **Comments**: Require team member's comment before building PRs + +### Build Configurations + +Samples should build for all supported configurations: +- Platforms: x64, x86, ARM64 +- Configurations: Debug, Release +- Minimum Windows version: Windows 10 version 1809 (build 17763) + +### Status Check Integration + +Add your pipeline to branch protection rules at: +`https://github.com/microsoft/WindowsAppSDK-Samples/settings/branches` + +Ensure the full `SamplesCI-` check is added, not individual job configurations. diff --git a/.github/instructions/csharp.instructions.md b/.github/instructions/csharp.instructions.md new file mode 100644 index 000000000..a93658bf2 --- /dev/null +++ b/.github/instructions/csharp.instructions.md @@ -0,0 +1,79 @@ +--- +description: 'Guidelines for C# Windows App SDK samples' +applyTo: '**/*.cs' +--- + +# C# Windows App SDK Development + +Guidelines for writing C# samples that demonstrate Windows App SDK features. + +## C# Instructions + +- Use C# language features appropriate for the target .NET version in the sample +- Write clear and concise comments explaining API usage patterns +- Focus on demonstrating Windows App SDK APIs, not general application architecture + +## General Instructions + +- Keep samples **complete but simple** – demonstrate correct API usage without excessive abstraction +- Follow **scenario-based design** – each scenario covers one way of using the API +- Handle edge cases with clear exception handling +- Comment on why certain Windows App SDK patterns are used + +## Naming Conventions + +- Follow PascalCase for component names, method names, and public members +- Use camelCase for private fields and local variables +- Prefix interface names with "I" (e.g., IWindowService) + +## Formatting + +- Apply code-formatting style defined in `.editorconfig` at repo root +- Prefer file-scoped namespace declarations +- Insert a newline before the opening curly brace (Allman style) +- Use pattern matching and switch expressions where they improve clarity +- Use `nameof` instead of string literals when referring to member names + +## Code Analysis + +- All code must pass **StyleCop.Analyzers** rules without warnings +- All code must pass **Microsoft.CodeAnalysis.NetAnalyzers** (CA rules) without warnings +- Suppress warnings only with justification comments when absolutely necessary +- Common rules to follow: + - [StyleCop.Analyzers rules](https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/DOCUMENTATION.md) + - [Code quality rules (CA)](https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/) + - [Code style rules (IDE)](https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/) + +## Nullable Reference Types + +- Declare variables non-nullable, and check for `null` at entry points +- Always use `is null` or `is not null` instead of `== null` or `!= null` +- Trust the C# null annotations and don't add null checks when the type system says a value cannot be null + +## Windows App SDK Patterns + +### App Lifecycle and Activation + +- Demonstrate proper activation handling (file, protocol, launch) +- Show single-instance patterns using `AppInstance` +- Handle restart and state persistence scenarios + +### WinUI 3 and XAML + +- Use x:Bind for data binding where possible +- Demonstrate proper resource management and theming +- Show Window and navigation patterns + +### Packaging and Deployment + +- Support both packaged (MSIX) and unpackaged scenarios where applicable +- Use `WindowsPackageType` appropriately in project files +- Demonstrate self-contained deployment patterns when relevant + +## Copyright Headers + +All C# files must include: +```csharp +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +``` diff --git a/.github/instructions/instructions.instructions.md b/.github/instructions/instructions.instructions.md new file mode 100644 index 000000000..107c1cf2c --- /dev/null +++ b/.github/instructions/instructions.instructions.md @@ -0,0 +1,256 @@ +--- +description: 'Guidelines for creating high-quality custom instruction files for GitHub Copilot' +applyTo: '**/*.instructions.md' +--- + +# Custom Instructions File Guidelines + +Instructions for creating effective and maintainable custom instruction files that guide GitHub Copilot in generating domain-specific code and following project conventions. + +## Project Context + +- Target audience: Developers and GitHub Copilot working with domain-specific code +- File format: Markdown with YAML frontmatter +- File naming convention: filename stem in lowercase-with-hyphens plus the `.instructions.md` suffix (e.g., stem `react-best-practices` → `react-best-practices.instructions.md`) +- Location: `.github/instructions/` directory +- Purpose: Provide context-aware guidance for code generation, review, and documentation + +## Required Frontmatter + +Every instruction file must include YAML frontmatter with the following fields: + +```yaml +--- +description: 'Brief description of the instruction purpose and scope' +applyTo: 'glob pattern for target files (e.g., **/*.ts, **/*.py)' +--- +``` + +### Frontmatter Guidelines + +- **description**: Single-quoted string, 1-500 characters, clearly stating the purpose +- **applyTo**: Glob pattern(s) specifying which files these instructions apply to + - Single pattern: `'**/*.ts'` + - Multiple patterns: `'**/*.ts, **/*.tsx, **/*.js'` + - Specific files: `'src/**/*.py'` + - All files: `'**'` + +## File Structure + +A well-structured instruction file should include the following sections: + +### 1. Title and Overview + +- Clear, descriptive title using `#` heading +- Brief introduction explaining the purpose and scope +- Optional: Project context section with key technologies and versions + +### 2. Core Sections + +Organize content into logical sections based on the domain: + +- **General Instructions**: High-level guidelines and principles +- **Best Practices**: Recommended patterns and approaches +- **Code Standards**: Naming conventions, formatting, style rules +- **Architecture/Structure**: Project organization and design patterns +- **Common Patterns**: Frequently used implementations +- **Security**: Security considerations (if applicable) +- **Performance**: Optimization guidelines (if applicable) +- **Testing**: Testing standards and approaches (if applicable) + +### 3. Examples and Code Snippets + +Provide concrete examples with clear labels: + +```markdown +### Good Example +\`\`\`language +// Recommended approach +code example here +\`\`\` + +### Bad Example +\`\`\`language +// Avoid this pattern +code example here +\`\`\` +``` + +### 4. Validation and Verification (Optional but Recommended) + +- Build commands to verify code +- Lint checks and formatting tools +- Testing requirements +- Verification steps + +## Content Guidelines + +### Writing Style + +- Use clear, concise language +- Write in imperative mood ("Use", "Implement", "Avoid") +- Be specific and actionable +- Avoid ambiguous terms like "should", "might", "possibly" +- Use bullet points and lists for readability +- Keep sections focused and scannable + +### Best Practices + +- **Be Specific**: Provide concrete examples rather than abstract concepts +- **Show Why**: Explain the reasoning behind recommendations when it adds value +- **Use Tables**: For comparing options, listing rules, or showing patterns +- **Include Examples**: Real code snippets are more effective than descriptions +- **Stay Current**: Reference current versions and best practices +- **Link Resources**: Include official documentation and authoritative sources + +### Common Patterns to Include + +1. **Naming Conventions**: How to name variables, functions, classes, files +2. **Code Organization**: File structure, module organization, import order +3. **Error Handling**: Preferred error handling patterns +4. **Dependencies**: How to manage and document dependencies +5. **Comments and Documentation**: When and how to document code +6. **Version Information**: Target language/framework versions + +## Patterns to Follow + +### Bullet Points and Lists + +```markdown +## Security Best Practices + +- Always validate user input before processing +- Use parameterized queries to prevent SQL injection +- Store secrets in environment variables, never in code +- Implement proper authentication and authorization +- Enable HTTPS for all production endpoints +``` + +### Tables for Structured Information + +```markdown +## Common Issues + +| Issue | Solution | Example | +| ---------------- | ------------------- | ----------------------------- | +| Magic numbers | Use named constants | `const MAX_RETRIES = 3` | +| Deep nesting | Extract functions | Refactor nested if statements | +| Hardcoded values | Use configuration | Store API URLs in config | +``` + +### Code Comparison + +```markdown +### Good Example - Using TypeScript interfaces +\`\`\`typescript +interface User { + id: string; + name: string; + email: string; +} + +function getUser(id: string): User { + // Implementation +} +\`\`\` + +### Bad Example - Using any type +\`\`\`typescript +function getUser(id: any): any { + // Loses type safety +} +\`\`\` +``` + +### Conditional Guidance + +```markdown +## Framework Selection + +- **For small projects**: Use Minimal API approach +- **For large projects**: Use controller-based architecture with clear separation +- **For microservices**: Consider domain-driven design patterns +``` + +## Patterns to Avoid + +- **Overly verbose explanations**: Keep it concise and scannable +- **Outdated information**: Always reference current versions and practices +- **Ambiguous guidelines**: Be specific about what to do or avoid +- **Missing examples**: Abstract rules without concrete code examples +- **Contradictory advice**: Ensure consistency throughout the file +- **Copy-paste from documentation**: Add value by distilling and providing context + +## Testing Your Instructions + +Before finalizing instruction files: + +1. **Test with Copilot**: Try the instructions with actual prompts in VS Code +2. **Verify Examples**: Ensure code examples are correct and run without errors +3. **Check Glob Patterns**: Confirm `applyTo` patterns match intended files + +## Example Structure + +Here's a minimal example structure for a new instruction file: + +```markdown +--- +description: 'Brief description of purpose' +applyTo: '**/*.ext' +--- + +# Technology Name Development + +Brief introduction and context. + +## General Instructions + +- High-level guideline 1 +- High-level guideline 2 + +## Best Practices + +- Specific practice 1 +- Specific practice 2 + +## Code Standards + +### Naming Conventions +- Rule 1 +- Rule 2 + +### File Organization +- Structure 1 +- Structure 2 + +## Common Patterns + +### Pattern 1 +Description and example + +\`\`\`language +code example +\`\`\` + +### Pattern 2 +Description and example + +## Validation + +- Build command: `command to verify` +- Lint checks: `command to lint` +- Testing: `command to test` +``` + +## Maintenance + +- Review instructions when dependencies or frameworks are updated +- Update examples to reflect current best practices +- Remove outdated patterns or deprecated features +- Add new patterns as they emerge in the community +- Keep glob patterns accurate as project structure evolves + +## Additional Resources + +- [Custom Instructions Documentation](https://code.visualstudio.com/docs/copilot/customization/custom-instructions) +- [Awesome Copilot Instructions](https://github.com/github/awesome-copilot/tree/main/instructions) diff --git a/.github/instructions/powershell.instructions.md b/.github/instructions/powershell.instructions.md new file mode 100644 index 000000000..97dbfb50a --- /dev/null +++ b/.github/instructions/powershell.instructions.md @@ -0,0 +1,394 @@ +--- +applyTo: '**/*.ps1,**/*.psm1' +description: 'PowerShell cmdlet and scripting best practices based on Microsoft guidelines' +--- + +# PowerShell Cmdlet Development Guidelines + +This guide provides PowerShell-specific instructions to help GitHub Copilot generate idiomatic, +safe, and maintainable scripts. It aligns with Microsoft’s PowerShell cmdlet development guidelines. +## Strict Mode and Exit Code Requirements + +**All scripts must enforce strict mode and proper exit codes:** + +```powershell +Set-StrictMode -Version 2.0 +$ErrorActionPreference = 'Stop' + +# Script logic here... + +# Exit with appropriate code +exit 0 # Success +# exit 1 # Failure +``` + +### Strict Mode Rules + +- **Always use `Set-StrictMode -Version 2.0`** at the top of every script +- This catches common errors: uninitialized variables, non-existent properties, function calls like methods +- Combined with `$ErrorActionPreference = 'Stop'` for fail-fast behavior + +### Exit Code Requirements + +- **Exit 0** for successful completion +- **Exit non-zero** (typically 1) for any failure +- Use `try/catch/finally` with explicit exit codes: + +```powershell +try { + # Main script logic + exit 0 +} catch { + Write-Error "Script failed: $_" + exit 1 +} +``` + +- For CI/build scripts, ensure the exit code reflects the actual success/failure state +- Never silently swallow errors that should fail the build +## Naming Conventions + +- **Verb-Noun Format:** + - Use approved PowerShell verbs (Get-Verb) + - Use singular nouns + - PascalCase for both verb and noun + - Avoid special characters and spaces + +- **Parameter Names:** + - Use PascalCase + - Choose clear, descriptive names + - Use singular form unless always multiple + - Follow PowerShell standard names + +- **Variable Names:** + - Use PascalCase for public variables + - Use camelCase for private variables + - Avoid abbreviations + - Use meaningful names + +- **Alias Avoidance:** + - Use full cmdlet names + - Avoid using aliases in scripts (e.g., use Get-ChildItem instead of gci) + - Document any custom aliases + - Use full parameter names + +### Example + +```powershell +function Get-UserProfile { + [CmdletBinding()] + param( + [Parameter(Mandatory)] + [string]$Username, + + [Parameter()] + [ValidateSet('Basic', 'Detailed')] + [string]$ProfileType = 'Basic' + ) + + process { + # Logic here + } +} +``` + +## Parameter Design + +- **Standard Parameters:** + - Use common parameter names (`Path`, `Name`, `Force`) + - Follow built-in cmdlet conventions + - Use aliases for specialized terms + - Document parameter purpose + +- **Parameter Names:** + - Use singular form unless always multiple + - Choose clear, descriptive names + - Follow PowerShell conventions + - Use PascalCase formatting + +- **Type Selection:** + - Use common .NET types + - Implement proper validation + - Consider ValidateSet for limited options + - Enable tab completion where possible + +- **Switch Parameters:** + - Use [switch] for boolean flags + - Avoid $true/$false parameters + - Default to $false when omitted + - Use clear action names + +### Example + +```powershell +function Set-ResourceConfiguration { + [CmdletBinding()] + param( + [Parameter(Mandatory)] + [string]$Name, + + [Parameter()] + [ValidateSet('Dev', 'Test', 'Prod')] + [string]$Environment = 'Dev', + + [Parameter()] + [switch]$Force, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [string[]]$Tags + ) + + process { + # Logic here + } +} +``` + +## Pipeline and Output + +- **Pipeline Input:** + - Use `ValueFromPipeline` for direct object input + - Use `ValueFromPipelineByPropertyName` for property mapping + - Implement Begin/Process/End blocks for pipeline handling + - Document pipeline input requirements + +- **Output Objects:** + - Return rich objects, not formatted text + - Use PSCustomObject for structured data + - Avoid Write-Host for data output + - Enable downstream cmdlet processing + +- **Pipeline Streaming:** + - Output one object at a time + - Use process block for streaming + - Avoid collecting large arrays + - Enable immediate processing + +- **PassThru Pattern:** + - Default to no output for action cmdlets + - Implement `-PassThru` switch for object return + - Return modified/created object with `-PassThru` + - Use verbose/warning for status updates + +### Example + +```powershell +function Update-ResourceStatus { + [CmdletBinding()] + param( + [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] + [string]$Name, + + [Parameter(Mandatory)] + [ValidateSet('Active', 'Inactive', 'Maintenance')] + [string]$Status, + + [Parameter()] + [switch]$PassThru + ) + + begin { + Write-Verbose 'Starting resource status update process' + $timestamp = Get-Date + } + + process { + # Process each resource individually + Write-Verbose "Processing resource: $Name" + + $resource = [PSCustomObject]@{ + Name = $Name + Status = $Status + LastUpdated = $timestamp + UpdatedBy = $env:USERNAME + } + + # Only output if PassThru is specified + if ($PassThru.IsPresent) { + Write-Output $resource + } + } + + end { + Write-Verbose 'Resource status update process completed' + } +} +``` + +## Error Handling and Safety + +- **ShouldProcess Implementation:** + - Use `[CmdletBinding(SupportsShouldProcess = $true)]` + - Set appropriate `ConfirmImpact` level + - Call `$PSCmdlet.ShouldProcess()` for system changes + - Use `ShouldContinue()` for additional confirmations + +- **Message Streams:** + - `Write-Verbose` for operational details with `-Verbose` + - `Write-Warning` for warning conditions + - `Write-Error` for non-terminating errors + - `throw` for terminating errors + - Avoid `Write-Host` except for user interface text + +- **Error Handling Pattern:** + - Use try/catch blocks for error management + - Set appropriate ErrorAction preferences + - Return meaningful error messages + - Use ErrorVariable when needed + - Include proper terminating vs non-terminating error handling + - In advanced functions with `[CmdletBinding()]`, prefer `$PSCmdlet.WriteError()` over `Write-Error` + - In advanced functions with `[CmdletBinding()]`, prefer `$PSCmdlet.ThrowTerminatingError()` over `throw` + - Construct proper ErrorRecord objects with category, target, and exception details + +- **Non-Interactive Design:** + - Accept input via parameters + - Avoid `Read-Host` in scripts + - Support automation scenarios + - Document all required inputs + +### Example + +```powershell +function Remove-UserAccount { + [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] + param( + [Parameter(Mandatory, ValueFromPipeline)] + [ValidateNotNullOrEmpty()] + [string]$Username, + + [Parameter()] + [switch]$Force + ) + + begin { + Write-Verbose 'Starting user account removal process' + $ErrorActionPreference = 'Stop' + } + + process { + try { + # Validation + if (-not (Test-UserExists -Username $Username)) { + $errorRecord = [System.Management.Automation.ErrorRecord]::new( + [System.Exception]::new("User account '$Username' not found"), + 'UserNotFound', + [System.Management.Automation.ErrorCategory]::ObjectNotFound, + $Username + ) + $PSCmdlet.WriteError($errorRecord) + return + } + + # Confirmation + $shouldProcessMessage = "Remove user account '$Username'" + if ($Force -or $PSCmdlet.ShouldProcess($Username, $shouldProcessMessage)) { + Write-Verbose "Removing user account: $Username" + + # Main operation + Remove-ADUser -Identity $Username -ErrorAction Stop + Write-Warning "User account '$Username' has been removed" + } + } catch [Microsoft.ActiveDirectory.Management.ADException] { + $errorRecord = [System.Management.Automation.ErrorRecord]::new( + $_.Exception, + 'ActiveDirectoryError', + [System.Management.Automation.ErrorCategory]::NotSpecified, + $Username + ) + $PSCmdlet.ThrowTerminatingError($errorRecord) + } catch { + $errorRecord = [System.Management.Automation.ErrorRecord]::new( + $_.Exception, + 'UnexpectedError', + [System.Management.Automation.ErrorCategory]::NotSpecified, + $Username + ) + $PSCmdlet.ThrowTerminatingError($errorRecord) + } + } + + end { + Write-Verbose 'User account removal process completed' + } +} +``` + +## Documentation and Style + +- **Comment-Based Help:** Include comment-based help for any public-facing function or cmdlet. Inside the function, add a `<# ... #>` help comment with at least: + - `.SYNOPSIS` Brief description + - `.DESCRIPTION` Detailed explanation + - `.EXAMPLE` sections with practical usage + - `.PARAMETER` descriptions + - `.OUTPUTS` Type of output returned + - `.NOTES` Additional information + +- **Consistent Formatting:** + - Follow consistent PowerShell style + - Use proper indentation (4 spaces recommended) + - Opening braces on same line as statement + - Closing braces on new line + - Use line breaks after pipeline operators + - PascalCase for function and parameter names + - Avoid unnecessary whitespace + +- **Pipeline Support:** + - Implement Begin/Process/End blocks for pipeline functions + - Use ValueFromPipeline where appropriate + - Support pipeline input by property name + - Return proper objects, not formatted text + +- **Avoid Aliases:** Use full cmdlet names and parameters + - Avoid using aliases in scripts (e.g., use Get-ChildItem instead of gci); aliases are acceptable for interactive shell use. + - Use `Where-Object` instead of `?` or `where` + - Use `ForEach-Object` instead of `%` + - Use `Get-ChildItem` instead of `ls` or `dir` + +## Full Example: End-to-End Cmdlet Pattern + +```powershell +function New-Resource { + [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] + param( + [Parameter(Mandatory = $true, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true)] + [ValidateNotNullOrEmpty()] + [string]$Name, + + [Parameter()] + [ValidateSet('Development', 'Production')] + [string]$Environment = 'Development' + ) + + begin { + Write-Verbose 'Starting resource creation process' + } + + process { + try { + if ($PSCmdlet.ShouldProcess($Name, 'Create new resource')) { + # Resource creation logic here + Write-Output ([PSCustomObject]@{ + Name = $Name + Environment = $Environment + Created = Get-Date + }) + } + } catch { + $errorRecord = [System.Management.Automation.ErrorRecord]::new( + $_.Exception, + 'ResourceCreationFailed', + [System.Management.Automation.ErrorCategory]::NotSpecified, + $Name + ) + $PSCmdlet.ThrowTerminatingError($errorRecord) + } + } + + end { + Write-Verbose 'Completed resource creation process' + } +} +``` diff --git a/.github/instructions/prompt.instructions.md b/.github/instructions/prompt.instructions.md new file mode 100644 index 000000000..a232edb97 --- /dev/null +++ b/.github/instructions/prompt.instructions.md @@ -0,0 +1,88 @@ +--- +description: 'Guidelines for creating high-quality prompt files for GitHub Copilot' +applyTo: '**/*.prompt.md' +--- + +# Copilot Prompt Files Guidelines + +Instructions for creating effective and maintainable prompt files that guide GitHub Copilot in delivering consistent, high-quality outcomes across any repository. + +## Scope and Principles +- Target audience: maintainers and contributors authoring reusable prompts for Copilot Chat. +- Goals: predictable behaviour, clear expectations, minimal permissions, and portability across repositories. +- Primary references: VS Code documentation on prompt files and organization-specific conventions. + +## Frontmatter Requirements + +Every prompt file should include YAML frontmatter with the following fields: + +### Required/Recommended Fields + +| Field | Required | Description | +|-------|----------|-------------| +| `description` | Recommended | A short description of the prompt (single sentence, actionable outcome) | +| `name` | Optional | The name shown after typing `/` in chat. Defaults to filename if not specified | +| `agent` | Recommended | The agent to use: `ask`, `edit`, `agent`, or a custom agent name. Defaults to current agent | +| `model` | Optional | The language model to use. Defaults to currently selected model | +| `tools` | Optional | List of tool/tool set names available for this prompt | +| `argument-hint` | Optional | Hint text shown in chat input to guide user interaction | + +### Guidelines + +- Use consistent quoting (single quotes recommended) and keep one field per line for readability and version control clarity +- If `tools` are specified and current agent is `ask` or `edit`, the default agent becomes `agent` +- Preserve any additional metadata (`language`, `tags`, `visibility`, etc.) required by your organization + +## File Naming and Placement +- Use kebab-case filenames ending with `.prompt.md` and store them under `.github/prompts/` unless your workspace standard specifies another directory. +- Provide a short filename that communicates the action (for example, `generate-readme.prompt.md` rather than `prompt1.prompt.md`). + +## Body Structure +- Start with an `#` level heading that matches the prompt intent so it surfaces well in Quick Pick search. +- Organize content with predictable sections. Recommended baseline: `Mission` or `Primary Directive`, `Scope & Preconditions`, `Inputs`, `Workflow` (step-by-step), `Output Expectations`, and `Quality Assurance`. +- Adjust section names to fit the domain, but retain the logical flow: why → context → inputs → actions → outputs → validation. +- Reference related prompts or instruction files using relative links to aid discoverability. + +## Input and Context Handling +- Use `${input:variableName[:placeholder]}` for required values and explain when the user must supply them. Provide defaults or alternatives where possible. +- Call out contextual variables such as `${selection}`, `${file}`, `${workspaceFolder}` only when they are essential, and describe how Copilot should interpret them. +- Document how to proceed when mandatory context is missing (for example, “Request the file path and stop if it remains undefined”). + +## Tool and Permission Guidance +- Limit `tools` to the smallest set that enables the task. List them in the preferred execution order when the sequence matters. +- If the prompt inherits tools from a chat mode, mention that relationship and state any critical tool behaviours or side effects. +- Warn about destructive operations (file creation, edits, terminal commands) and include guard rails or confirmation steps in the workflow. + +## Instruction Tone and Style +- Write in direct, imperative sentences targeted at Copilot (for example, “Analyze”, “Generate”, “Summarize”). +- Keep sentences short and unambiguous, following Google Developer Documentation translation best practices to support localization. +- Avoid idioms, humor, or culturally specific references; favor neutral, inclusive language. + +## Output Definition +- Specify the format, structure, and location of expected results (for example, “Create an architecture decision record file using the template below, such as `docs/architecture-decisions/record-XXXX.md`). +- Include success criteria and failure triggers so Copilot knows when to halt or retry. +- Provide validation steps—manual checks, automated commands, or acceptance criteria lists—that reviewers can execute after running the prompt. + +## Examples and Reusable Assets +- Embed Good/Bad examples or scaffolds (Markdown templates, JSON stubs) that the prompt should produce or follow. +- Maintain reference tables (capabilities, status codes, role descriptions) inline to keep the prompt self-contained. Update these tables when upstream resources change. +- Link to authoritative documentation instead of duplicating lengthy guidance. + +## Quality Assurance Checklist +- [ ] Frontmatter fields are complete, accurate, and least-privilege. +- [ ] Inputs include placeholders, default behaviours, and fallbacks. +- [ ] Workflow covers preparation, execution, and post-processing without gaps. +- [ ] Output expectations include formatting and storage details. +- [ ] Validation steps are actionable (commands, diff checks, review prompts). +- [ ] Security, compliance, and privacy policies referenced by the prompt are current. +- [ ] Prompt executes successfully in VS Code (`Chat: Run Prompt`) using representative scenarios. + +## Maintenance Guidance +- Version-control prompts alongside the code they affect; update them when dependencies, tooling, or review processes change. +- Review prompts periodically to ensure tool lists, model requirements, and linked documents remain valid. +- Coordinate with other repositories: when a prompt proves broadly useful, extract common guidance into instruction files or shared prompt packs. + +## Additional Resources +- [Prompt Files Documentation](https://code.visualstudio.com/docs/copilot/customization/prompt-files#_prompt-file-format) +- [Awesome Copilot Prompt Files](https://github.com/github/awesome-copilot/tree/main/prompts) +- [Tool Configuration](https://code.visualstudio.com/docs/copilot/chat/chat-agent-mode#_agent-mode-tools) diff --git a/.github/prompts/create-commit-title.prompt.md b/.github/prompts/create-commit-title.prompt.md new file mode 100644 index 000000000..bfdf81ba1 --- /dev/null +++ b/.github/prompts/create-commit-title.prompt.md @@ -0,0 +1,50 @@ +--- +agent: 'agent' +model: 'GPT-5.1-Codex-Max' +description: 'Generate an 80-character git commit title for the local diff' +--- + +# Generate Commit Title + +## Purpose +Provide a single-line, ready-to-paste git commit title (<= 80 characters) that reflects the most important local changes since `HEAD`. + +## Input to collect +- Run exactly one command to view the local diff: + ```@terminal + git diff HEAD + ``` + +## How to decide the title +1. From the diff, find the dominant area (e.g., `Samples/AppLifecycle/*`, `docs/**`) and the change type (new sample, bug fix, docs update, config tweak). +2. Draft an imperative, plain-ASCII title that: + - Mentions the primary feature/sample when obvious (e.g., `AppLifecycle:` or `Docs:`) + - Stays within 80 characters and has no trailing punctuation + +## Final output +- Reply with only the commit title on a single line—no extra text. + +## PR title convention (when asked) +Use Conventional Commits style: + +`(): ` + +**Allowed types** +- feat, fix, docs, refactor, perf, test, build, ci, chore, sample + +**Scope rules** +- Use a short, WindowsAppSDK-Samples-focused scope (one word preferred). Common scopes: + - Core: `docs`, `build`, `ci`, `templates`, `repo` + - Features: `applifecycle`, `activation`, `instancing`, `restart`, `notifications`, `push`, `app-notifications`, `windowing`, `widgets`, `mica`, `textrendering`, `resourcemanagement`, `deployment`, `installer`, `unpackaged`, `islands`, `composition`, `input`, `customcontrols`, `backgroundtask`, `scenegraph`, `photoeditor`, `windowsai`, `windowsml` +- If unclear, pick the closest feature or sample area; omit only if unavoidable + +**Summary rules** +- Imperative, present tense (“add”, “update”, “remove”, “fix”) +- Keep it <= 72 characters when possible; be specific, avoid “misc changes” + +**Examples** +- `feat(applifecycle): add activation sample for file type associations` +- `fix(notifications): correct push notification channel registration` +- `docs(windowing): document presenter configuration options` +- `build(ci): add SamplesCI pipeline for new feature` +- `sample(widgets): add weather widget implementation` diff --git a/.github/prompts/create-pr-summary.prompt.md b/.github/prompts/create-pr-summary.prompt.md new file mode 100644 index 000000000..20201c477 --- /dev/null +++ b/.github/prompts/create-pr-summary.prompt.md @@ -0,0 +1,25 @@ +--- +agent: 'agent' +model: 'GPT-5.1-Codex-Max' +description: 'Generate a WindowsAppSDK-Samples-ready pull request description from the local diff' +--- + +# Generate PR Summary + +**Goal:** Produce a ready-to-paste PR title and description that follows WindowsAppSDK-Samples conventions by comparing the current branch against a user-selected target branch. + +**Repo guardrails:** +- Treat `docs/pull_request_template.md` as the single source of truth; load it at runtime instead of embedding hardcoded content in this prompt. +- Preserve section order from the template but only surface checklist lines that are relevant for the detected changes, filling them with `[x]`/`[ ]` as appropriate. +- Cite touched paths with inline backticks, matching the guidance in `.github/copilot-instructions.md`. +- Call out build/test validation explicitly: state which platforms (x64, x86, ARM64) and configurations (Debug, Release) were tested, or why testing was not applicable. + +**Workflow:** +1. Determine the target branch from user context; default to `main` when no branch is supplied. +2. Run `git status --short` once to surface uncommitted files that may influence the summary. +3. Run `git diff ...HEAD` a single time to review the detailed changes. Only when confidence stays low dig deeper with focused calls such as `git diff ...HEAD -- `. +4. From the diff, capture impacted areas (features, samples), key file changes, behavioral risks, and noteworthy edge cases. +5. Confirm validation: list builds and tests executed with results, or state why they were skipped in line with repo guidance. +6. Load `docs/pull_request_template.md`, mirror its section order, and populate it with the gathered facts. Include only relevant checklist entries, marking them `[x]/[ ]` and noting any intentional omissions as "N/A". +7. Present the filled template inside a fenced ```markdown code block with no extra commentary so it is ready to paste into a PR, clearly flagging any placeholders that still need user input. +8. Prepend the PR title above the filled template. Construct the PR title using the same Conventional Commit type/scope rules defined for commit titles in `.github/prompts/create-commit-title.prompt.md` (this repo intentionally applies the commit-title convention to PR titles); pick the dominant component from the diff and keep the title concise and imperative. diff --git a/.github/prompts/fix-issue.prompt.md b/.github/prompts/fix-issue.prompt.md new file mode 100644 index 000000000..cd4b154e1 --- /dev/null +++ b/.github/prompts/fix-issue.prompt.md @@ -0,0 +1,68 @@ +--- +agent: 'agent' +model: 'GPT-5.1-Codex-Max' +description: 'Execute the fix for a GitHub issue using the previously generated implementation plan' +--- + +# Fix GitHub Issue + +## Dependencies +Source review prompt (for generating the implementation plan if missing): +- .github/prompts/review-issue.prompt.md + +Required plan file (single source of truth): +- Generated Files/issueReview/{{issue_number}}/implementation-plan.md + +## Dependency Handling +1) If `implementation-plan.md` exists → proceed. +2) If missing → run the review prompt: + - Invoke: `.github/prompts/review-issue.prompt.md` + - Pass: `issue_number={{issue_number}}` + - Then re-check for `implementation-plan.md`. +3) If still missing → stop and generate: + - `Generated Files/issueFix/{{issue_number}}/manual-steps.md` containing: + “implementation-plan.md not found; please run .github/prompts/review-issue.prompt.md for #{{issue_number}}.” + +# GOAL +For **#{{issue_number}}**: +- Use implementation-plan.md as the single authority. +- Apply code and test changes directly in the repository. +- Produce a PR-ready description. + +# OUTPUT FILES +1) Generated Files/issueFix/{{issue_number}}/pr-description.md +2) Generated Files/issueFix/{{issue_number}}/manual-steps.md # only if human interaction or external setup is required + +# EXECUTION RULES +1) Read implementation-plan.md and execute: + - Layers & Files → edit/create as listed + - Pattern Choices → follow repository conventions + - Fundamentals (perf, security, compatibility, accessibility) + - Logging & Exceptions + - Telemetry (only if explicitly included in the plan) + - Risks & Mitigations + - Tests to Add +2) Locate affected files via `rg` or `git grep`. +3) Add/update tests to enforce the fixed behavior. +4) If any ambiguity exists, add: +// TODO(Human input needed): +5) Verify locally: build & tests run successfully. + +# PR DESCRIPTION +Generate the PR description by invoking `.github/prompts/create-pr-summary.prompt.md`. +Append `Closes #{{issue_number}}` to the generated description. +Save the result to `Generated Files/issueFix/{{issue_number}}/pr-description.md`. + +# manual-steps.md (only if needed) +- List required human actions: secrets, config, approvals, missing info, or code comments requiring human decisions. + +# IMPORTANT +- Apply code and tests directly; do not produce patch files. +- Follow implementation-plan.md as the source of truth. +- Insert comments for human review where a decision or input is required. +- Use repository conventions and deterministic, minimal changes. + +# FINALIZE +- Write pr-description.md +- Write manual-steps.md only if needed +- Print concise success message or note items requiring human interaction diff --git a/.github/prompts/review-issue.prompt.md b/.github/prompts/review-issue.prompt.md new file mode 100644 index 000000000..769823fd3 --- /dev/null +++ b/.github/prompts/review-issue.prompt.md @@ -0,0 +1,160 @@ +--- +agent: 'agent' +model: 'GPT-5.1-Codex-Max' +description: 'Review a GitHub issue, score it (0-100), and generate an implementation plan' +--- + +# Review GitHub Issue + +## Goal +For **#{{issue_number}}** produce: +1) `Generated Files/issueReview/{{issue_number}}/overview.md` +2) `Generated Files/issueReview/{{issue_number}}/implementation-plan.md` + +## Inputs +Figure out required inputs {{issue_number}} from the invocation context; if anything is missing, ask for the value or note it as a gap. + +# CONTEXT (brief) +Ground evidence using `gh issue view {{issue_number}} --json number,title,body,author,createdAt,updatedAt,state,labels,milestone,reactions,comments,linkedPullRequests`, and download images to better understand the issue context. +Locate source code in the current workspace; feel free to use `rg`/`git grep`. Link related issues and PRs. + +# OVERVIEW.MD +## Summary +Issue, state, milestone, labels. **Signals**: 👍/❤️/👎, comment count, last activity, linked PRs. + +## At-a-Glance Score Table +Present all ratings in a compact table for quick scanning: + +| Dimension | Score | Assessment | Key Drivers | +|-----------|-------|------------|-------------| +| **A) Business Importance** | X/100 | Low/Medium/High | Top 2 factors with scores | +| **B) Community Excitement** | X/100 | Low/Medium/High | Top 2 factors with scores | +| **C) Technical Feasibility** | X/100 | Low/Medium/High | Top 2 factors with scores | +| **D) Requirement Clarity** | X/100 | Low/Medium/High | Top 2 factors with scores | +| **Overall Priority** | X/100 | Low/Medium/High/Critical | Average or weighted summary | +| **Effort Estimate** | X days (T-shirt) | XS/S/M/L/XL/XXL/Epic | Type: bug/feature/chore | +| **Similar Issues Found** | X open, Y closed | — | Quick reference to related work | +| **Potential Assignees** | @username, @username | — | Top contributors to module | + +**Assessment bands**: 0-25 Low, 26-50 Medium, 51-75 High, 76-100 Critical + +## Ratings (0–100) — add evidence & short rationale +### A) Business Importance +- Labels (priority/security/regression): **≤35** +- Milestone/roadmap: **≤25** +- Customer/contract impact: **≤20** +- Unblocks/platform leverage: **≤20** +### B) Community Excitement +- 👍+❤️ normalized: **≤45** +- Comment volume & unique participants: **≤25** +- Recent activity (≤30d): **≤15** +- Duplicates/related issues: **≤15** +### C) Technical Feasibility +- Contained surface/clear seams: **≤30** +- Existing patterns/utilities: **≤25** +- Risk (perf/sec/compat) manageable: **≤25** +- Testability & CI support: **≤20** +### D) Requirement Clarity +- Behavior/repro/constraints: **≤60** +- Non-functionals (perf/sec/i18n/a11y): **≤25** +- Decision owners/acceptance signals: **≤15** + +## Effort +Days + **T-shirt** (XS 0.5–1d, S 1–2, M 2–4, L 4–7, XL 7–14, XXL 14–30, Epic >30). +Type/level: bug/feature/chore/docs/refactor/test-only; severity/value tier. + +## Suggested Actions +Provide actionable recommendations for issue triage and assignment: + +### A) Requirement Clarification (if Clarity score <50) +**When Requirement Clarity (Dimension D) is Medium or Low:** +- Identify specific gaps in issue description: missing repro steps, unclear expected behavior, undefined acceptance criteria, missing non-functional requirements +- Draft 3-5 clarifying questions to post as issue comment +- Suggest additional information needed: screenshots, logs, environment details, OS version, Windows App SDK version, Visual Studio version, error messages +- If behavior is ambiguous, propose 2-3 interpretation scenarios and ask reporter to confirm +- Example questions: + - "Can you provide exact steps to reproduce this issue?" + - "What is the expected behavior vs. what you're actually seeing?" + - "Does this happen on Windows 10, 11, or both?" + - "Can you attach a screenshot or screen recording?" + +### B) Correct Label Suggestions +- Analyze issue type, sample area, and severity to suggest missing or incorrect labels +- Recommend labels from: `bug`, `enhancement`, `documentation`, `question`, `duplicate`, `needs-triage`, `needs-author-feedback`, `sample-`, etc. +- If Requirement Clarity is low (<50), add `needs-author-feedback` label +- If current labels are incorrect or incomplete, provide specific label changes with rationale + +### C) Find Similar Issues & Past Fixes +- Search for similar issues using `gh issue list --search "keywords" --state all --json number,title,state,closedAt` +- Identify patterns: duplicate issues, related bugs, or similar feature requests +- For closed issues, find linked PRs that fixed them: check `linkedPullRequests` in issue data +- Provide 3-5 examples of similar issues with format: `# - (closed by PR #<pr>)` or `(still open)` + +### D) Identify Subject Matter Experts +- Use git blame/log to find who fixed similar issues in the past +- Search for PR authors who touched relevant files: `git log --all --format='%aN' -- <file_paths> | sort | uniq -c | sort -rn | head -5` +- Check issue/PR history for frequent contributors to the affected module +- Suggest 2-3 potential assignees with context: `@<username> - <reason>` (e.g., "fixed similar sample issue in #12345", "maintains AppLifecycle samples") + +### E) Semantic Search for Related Work +- Use semantic_search tool to find similar issues, code patterns, or past discussions +- Search queries should include: issue keywords, module names, error messages, feature descriptions +- Cross-reference semantic results with GitHub issue search for comprehensive coverage + +**Output format for Suggested Actions section in overview.md:** +```markdown +## Suggested Actions + +### Clarifying Questions (if Clarity <50) +Post these questions as issue comment to gather missing information: +1. <question> +2. <question> +3. <question> + +**Recommended label**: `Needs-Author-Feedback` + +### Label Recommendations +- Add: `<label>` - <reason> +- Remove: `<label>` - <reason> +- Current labels are appropriate ✓ + +### Similar Issues Found +1. #<number> - <title> (<state>, closed by PR #<pr> on <date>) +2. #<number> - <title> (<state>) +... + +### Potential Assignees +- @<username> - <reason> +- @<username> - <reason> + +### Related Code/Discussions +- <semantic search findings> +``` + +# IMPLEMENTATION-PLAN.MD +1) **Problem Framing** — restate problem; current vs expected; scope boundaries. +2) **Layers & Files** — layers (UI/domain/data/infra/build). For each, list **files/dirs to modify** and **new files** (exact paths + why). Prefer repo patterns; cite examples/PRs. +3) **Pattern Choices** — reuse existing; if new, justify trade-offs & transition. +4) **Fundamentals** (brief plan or N/A + reason): +- Performance (hot paths, allocs, caching/streaming) +- Security (validation, authN/Z, secrets, SSRF/XSS/CSRF) +- G11N/L10N (resources, number/date, pluralization) +- Compatibility (public APIs, formats, OS/runtime/toolchain) +- Extensibility (DI seams, options/flags, plugin points) +- Accessibility (roles, labels, focus, keyboard, contrast) +- SOLID & repo conventions (naming, folders, dependency direction) +5) **Logging & Exception Handling** +- Where to log; levels; structured fields; correlation/traces. +- What to catch vs rethrow; retries/backoff; user-visible errors. +- **Privacy**: never log secrets/PII; redaction policy. +6) **Telemetry (optional — business metrics only)** +- Events/metrics (name, when, props); success signal; privacy/sampling; dashboards/alerts. +7) **Risks & Mitigations** — flags/canary/shadow-write/config guards. +8) **Task Breakdown (agent-ready)** — table (leave a blank line before the header so Markdown renders correctly): + +| Task | Intent | Files/Areas | Steps | Tests (brief) | Owner (Agent/Human) | Human interaction needed? (why) | +|---|---|---|---|---|---|---| + +9) **Tests to Add (only)** +- **Unit**: targets, cases (success/edge/error), mocks/fixtures, path, notes. +- **UI** (if applicable): flows, locator strategy, env/data/flags, path, flake mitigation. \ No newline at end of file diff --git a/.github/prompts/review-pr.prompt.md b/.github/prompts/review-pr.prompt.md new file mode 100644 index 000000000..0fa2fa114 --- /dev/null +++ b/.github/prompts/review-pr.prompt.md @@ -0,0 +1,184 @@ +--- +agent: 'agent' +model: 'GPT-5.1-Codex-Max' +description: 'Perform a comprehensive PR review with per-step Markdown and machine-readable outputs' +--- + +# Review Pull Request + +**Goal**: Given `{{pr_number}}`, run a *one-topic-per-step* review. Write files to `Generated Files/prReview/{{pr_number}}/` (replace `{{pr_number}}` with the integer). Emit machine‑readable blocks for a GitHub MCP to post review comments. + +## PR selection +Resolve the target PR using these fallbacks in order: +1. Parse the invocation text for an explicit identifier (first integer following patterns such as a leading hash and digits or the text `PR:` followed by digits). +2. If no PR is found yet, locate the newest `Generated Files/prReview/_batch/batch-overview-*.md` file (highest timestamp in filename, fallback newest mtime) and take the first entry in its `## PRs` list whose review folder is missing `00-OVERVIEW.md` or contains `__error.flag`. +3. If the batch file has no pending PRs, query assignments with `gh pr list --assignee @me --state open --json number,updatedAt --limit 20` and pick the most recently updated PR that does not already have a completed review folder. +4. If still unknown, run `gh pr view --json number` in the current branch and use that result when it is unambiguous. +5. If every step above fails, prompt the user for a PR number before proceeding. + +## Fetch PR data with `gh` +- `gh pr view {{pr_number}} --json number,baseRefName,headRefName,baseRefOid,headRefOid,changedFiles,files` +- `gh api repos/:owner/:repo/pulls/{{pr_number}}/files?per_page=250` # patches for line mapping + +### Incremental review workflow +1. **Check for existing review**: Read `Generated Files/prReview/{{pr_number}}/00-OVERVIEW.md` +2. **Extract state**: Parse `Last reviewed SHA:` from review metadata section +3. **Detect changes**: Compare last reviewed SHA with current PR head using `gh api repos/:owner/:repo/compare/{{last_sha}}...{{head_sha}} --jq '.commits | length, .files[].filename'` +4. **Analyze result**: + - If force-push detected (last SHA not in history) → Full review needed + - If commits added since last review → Review only changed files + - If no changes → Skip review (update iteration history with "No changes since last review") +5. **Apply smart filtering**: Use the file patterns in smart step filtering table to skip irrelevant steps +6. **Update metadata**: After completing review, save current `headRefOid` as `Last reviewed SHA:` in `00-OVERVIEW.md` + +## Output files +Folder: `Generated Files/prReview/{{pr_number}}/` +Files: `00-OVERVIEW.md`, `01-functionality.md`, `02-compatibility.md`, `03-performance.md`, `04-accessibility.md`, `05-security.md`, `06-localization.md`, `07-globalization.md`, `08-extensibility.md`, `09-solid-design.md`, `10-repo-patterns.md`, `11-docs-automation.md`, `12-code-comments.md`, `13-copilot-guidance.md` *(only if guidance md exists).* +- **Write-after-step rule:** Immediately after completing each TODO step, persist that step's markdown file before proceeding to the next. Generate `00-OVERVIEW.md` only after every step file has been refreshed for the current run. + +## Iteration management +- Determine the current review iteration by reading `00-OVERVIEW.md` (look for `Review iteration:`). If missing, assume iteration `1`. +- Extract the last reviewed SHA from `00-OVERVIEW.md` (look for `Last reviewed SHA:` in the review metadata section). If missing, this is iteration 1. +- **Incremental review detection**: + 1. Use `gh api repos/:owner/:repo/compare/{{last_sha}}...{{head_sha}}` to get delta analysis. + 2. Check if `last_sha` exists in the commit history; if not (force-push), do a full review. + 3. If incremental, review only the files listed in the compare response and apply smart step filtering (see below). +- Increment the iteration for each review run and propagate the new value to all step files and the overview. +- Preserve prior iteration notes by keeping/expanding an `## Iteration history` section in each markdown file, appending the newest summary under `### Iteration <N>`. +- Summaries should capture key deltas since the previous iteration so reruns can pick up context quickly. +- **After review completion**, update `Last reviewed SHA:` in `00-OVERVIEW.md` with the current `headRefOid` and update the timestamp. + +### Smart step filtering (incremental reviews only) +When performing incremental review, skip steps that are irrelevant based on changed file types: + +| File pattern | Required steps | Skippable steps | +| --- | --- | --- | +| `**/*.cs`, `**/*.cpp`, `**/*.h` | Functionality, Compatibility, Performance, Security, SOLID, Repo patterns, Code comments | (depends on files) | +| `**/*.resx`, `**/Resources/*.xaml` | Localization, Globalization | Most others | +| `**/*.md` (docs) | Docs & automation | Most others (unless copilot guidance) | +| `**/*copilot*.md`, `.github/prompts/*.md` | Copilot guidance, Docs & automation | Most others | +| `**/*.csproj`, `**/*.vcxproj`, `**/packages.config` | Compatibility, Security, Repo patterns | Localization, Globalization, Accessibility | +| `**/UI/**`, `**/*View.xaml` | Accessibility, Localization | Performance (unless perf-sensitive controls) | + +**Default**: If uncertain or files span multiple categories, run all applicable steps. When in doubt, be conservative and review more rather than less. + +## TODO steps (one concern each) +1) Functionality — Does the implementation correctly follows SDK patterns? +2) Compatibility — Windows 10 1809+, x64/x86/ARM64, Debug/Release configurations +3) Performance — No unnecessary allocations or blocking operations +4) Accessibility — Follows [accessibility checklist](https://docs.microsoft.com/windows/apps/design/accessibility/accessibility-checklist) +5) Security — No hardcoded secrets, proper input validation +6) Localization — Resources properly externalized where applicable +7) Globalization — Culture-aware formatting where applicable +8) Extensibility — Clear patterns for developers to adapt +9) SOLID principles — Clean, maintainable SDK code +10) Repo patterns — Follows [Coding-Guidelines.md](docs/Coding-Guidelines.md) conventions +11) Docs & automation — Documentation updated, CI pipeline configured +12) Code comments — Appropriate copyright headers, helpful inline comments +13) Copilot guidance (conditional): if changed folders contain `*copilot*.md` or `.github/prompts/*.md`, review diffs **against** that guidance and write `13-copilot-guidance.md` (omit if none). + +## Per-step file template (use verbatim) +```md +# <STEP TITLE> +**PR:** (populate with PR identifier) — Base:<baseRefName> Head:<headRefName> +**Review iteration:** ITERATION + +## Iteration history +- Maintain subsections titled `### Iteration N` in reverse chronological order (append the latest at the top) with 2–4 bullet highlights. + +### Iteration ITERATION +- <Latest key point 1> +- <Latest key point 2> + +## Checks executed +- List the concrete checks for *this step only* (5–10 bullets). + +## Findings +(If none, write **None**. Defaults have one or more blocks:) + +```mcp-review-comment +{"file":"relative/path.ext","start_line":123,"end_line":125,"severity":"high|medium|low|info","tags":["<step-slug>","pr-tag-here"],"related_files":["optional/other/file1"],"body":"Problem → Why it matters → Concrete fix. If spans multiple files, name them here."} +``` +Use the second tag to encode the PR number. + +``` +## Overview file (`00-OVERVIEW.md`) template +```md +# PR Review Overview — (populate with PR identifier) +**Review iteration:** ITERATION +**Changed files:** <n> | **High severity issues:** <count> + +## Review metadata +**Last reviewed SHA:** <headRefOid from gh pr view> +**Last review timestamp:** <ISO8601 timestamp> +**Review mode:** <Full|Incremental (N files changed since iteration X)> +**Base ref:** <baseRefName> +**Head ref:** <headRefName> + +## Step results +Write lines like: `01 Functionality — <OK|Issues|Skipped> (see 01-functionality.md)` … through step 13. +Mark steps as "Skipped" when using incremental review smart filtering. + +## Iteration history +- Maintain subsections titled `### Iteration N` mirroring the per-step convention with concise deltas and cross-links to the relevant step files. +- For incremental reviews, list the specific files that changed and which commits were added. +``` + +## Line numbers & multi‑file issues +- Map head‑side lines from `patch` hunks (`@@ -a,b +c,d @@` → new lines `+c..+c+d-1`). +- For cross‑file issues: set the primary `"file"`, list others in `"related_files"`, and name them in `"body"`. + +## Posting (for MCP) +- Parse all ```mcp-review-comment``` blocks across step files and post as PR review comments. +- If posting isn’t available, still write all files. + +## Constraint +Read/analyze only; don't modify code. Keep comments small, specific, and fix‑oriented. + +## Scratch cache for large PRs + +Create a local scratch workspace to progressively summarize diffs and reload state across runs. + +### Paths +- Root: `Generated Files/prReview/{{pr_number}}/__tmp/` +- Files: + - `index.jsonl` — append-only JSON Lines index of artifacts. + - `todo-queue.json` — pending items (files/chunks/steps). + - `rollup-<step>-v<N>.md` — iterative per-step aggregates. + - `file-<hash>.txt` — optional saved chunk text (when needed). + +### JSON schema (per line in `index.jsonl`) +```json +{"type":"chunk|summary|issue|crosslink", + "path":"relative/file.ext","chunk_id":"f-12","step":"functionality|compatibility|...", + "base_sha":"...", "head_sha":"...", "range":[start,end], "version":1, + "notes":"short text or key:value map", "created_utc":"ISO8601"} +``` + +### Phases (stateful; resume-safe) +0. **Discover** PR + SHAs: `gh pr view <PR> --json baseRefName,headRefName,baseRefOid,headRefOid,files`. +1. **Chunk** each changed file (head): split into ~300–600 LOC or ~4k chars; stable `chunk_id` = hash(path+start). + - Save `chunk` records. Optionally write `file-<hash>.txt` for expensive chunks. +2. **Summarize** per chunk: intent, APIs, risks per TODO step; emit `summary` records (≤600 tokens each). +3. **Issues**: convert findings to machine-readable blocks and emit `issue` records (later rendered to step MD). +4. **Rollups**: build/update `rollup-<step>-v<N>.md` from `summary`+`issue`. Keep prior versions. +5. **Finalize**: write per-step files + `00-OVERVIEW.md` from rollups. Post comments via MCP if available. + +### Re-use & token limits +- Always **reload** `index.jsonl` first; skip chunks with same `head_sha` and `range`. +- **Incremental review optimization**: When comparing SHAs returns a subset of changed files, load only chunks from those files. Reuse existing chunks/summaries for unchanged files. +- Prefer re-summarizing only changed chunks; merge chunk summaries → file summaries → step rollups. +- When context is tight, load only the minimal chunk text (or its saved `file-<hash>.txt`) needed for a comment. + +### Original vs diff +- Fetch base content when needed: prefer `git show <baseRefName>:<path>`; fallback `gh api repos/:owner/:repo/contents/<path>?ref=<base_sha>` (base64). +- Use patch hunks from `gh api .../pulls/<PR>/files` to compute **head** line numbers. + +### Queue-driven loop +- Seed `todo-queue.json` with all changed files. +- Process: chunk → summarize → detect issues → roll up. +- Append to `index.jsonl` after each step; never rewrite previous lines (append-only). + +### Hygiene +- `__tmp/` is implementation detail; do not include in final artifacts. +- It is safe to delete to force a clean pass; the next run rebuilds it. \ No newline at end of file diff --git a/.gitignore b/.gitignore index 04e537eaa..258022156 100644 --- a/.gitignore +++ b/.gitignore @@ -39,9 +39,6 @@ Samples/WindowsML/Resources/obj/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ -# Visual Studio code -.vscode/ - # Visual Studio 2017 auto generated files Generated\ Files/ diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..868a34ff8 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,17 @@ +{ + "github.copilot.chat.reviewSelection.instructions": [ + { + "file": ".github/prompts/review-pr.prompt.md" + } + ], + "github.copilot.chat.commitMessageGeneration.instructions": [ + { + "file": ".github/prompts/create-commit-title.prompt.md" + } + ], + "github.copilot.chat.pullRequestDescriptionGeneration.instructions": [ + { + "file": ".github/prompts/create-pr-summary.prompt.md" + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 000000000..ca2870584 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,70 @@ +{ + "version": "2.0.0", + + "inputs": [ + { + "id": "config", + "type": "pickString", + "description": "Configuration", + "options": ["Debug", "Release"], + "default": "Release" + }, + { + "id": "platform", + "type": "pickString", + "description": "Platform (auto = detect host)", + "options": ["auto", "x64", "x86", "arm64"], + "default": "auto" + } + ], + + "tasks": [ + { + "label": "Build: Current file's sample (default)", + "type": "shell", + "command": "pwsh", + "args": [ + "-NoProfile", + "-ExecutionPolicy", + "Bypass", + "-File", + "${workspaceFolder}\\build.ps1", + "-Platform", + "${input:platform}", + "-Configuration", + "${input:config}", + "-Sample", + "${fileDirname}" + ], + "group": { "kind": "build", "isDefault": true }, + "presentation": { + "reveal": "always", + "panel": "dedicated", + "clear": true + }, + "problemMatcher": "$msCompile" + }, + { + "label": "Build: All samples", + "type": "shell", + "command": "pwsh", + "args": [ + "-NoProfile", + "-ExecutionPolicy", + "Bypass", + "-File", + "${workspaceFolder}\\build.ps1", + "-Platform", + "${input:platform}", + "-Configuration", + "${input:config}" + ], + "presentation": { + "reveal": "always", + "panel": "dedicated", + "clear": true + }, + "problemMatcher": "$msCompile" + } + ] +} diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..145128617 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,73 @@ +# Windows App SDK Samples – AI Contributor Guide + +Comprehensive guidance for AI contributions to Windows App SDK Samples. + +## Quick Reference + +- **Build**: Use `build.ps1` or `build.cmd` at repo root (auto-detects platform, supports `-Sample <name>` for targeted builds) +- **Run**: Deploy and test samples on Desktop (x64, x86, ARM64) in Debug and Release configurations +- **Verify**: Run Windows App Certification Kit (WACK) on Release builds +- **Exit code 0 = success** – do not proceed if build fails + +### Build Examples +```powershell +./build.ps1 # Build all samples (auto-detect platform) +./build.ps1 -Sample AppLifecycle # Build only AppLifecycle sample +./build.ps1 -Platform arm64 -Configuration Debug # Specific platform and config +``` + +## Key Rules + +- Samples should be **complete but simple** – demonstrate correct API usage without excessive abstraction +- Follow **scenario-based design** – each scenario covers one way of using the API +- Support all platforms: x64, x86, ARM64 in both Debug and Release +- Set minimum supported OS version to Windows 10 version 1809 (build 17763) +- Include copyright headers in all source files +- Build clean with no warnings or errors + +## Project Structure + +Samples follow this organization: +``` +\Samples + \<FeatureName> + \<Language>-<UI Framework> +``` + +- **FeatureName**: Use simple English name (e.g., `TextRendering` not `DWriteCore`) +- **Language**: `cs` | `cpp` +- **UI Framework (C#)**: `winui` | `wpf` | `winforms` | `console` +- **UI Framework (C++)**: `winui` | `win32` | `console` | `directx` + +## Style Enforcement + +- **C#**: Follow `.editorconfig` at repo root (4-space indent, Allman braces, UTF-8 BOM) +- **C++**: Use C++/WinRT for new samples; some samples include `.clang-format` (check `Samples/WindowsML/`) +- **XAML**: Use consistent formatting + +## Copyright Headers + +For C#/C++/IDL files: +```csharp +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +``` + +For XAML files: +```xml +<!-- Copyright (c) Microsoft Corporation. + Licensed under the MIT License. --> +``` + +## When to Ask for Clarification + +- Ambiguous sample requirements after reviewing docs +- Cross-feature impact unclear +- API usage patterns not well documented + +## Detailed Documentation + +- [Samples Guidelines](/docs/samples-guidelines.md) – Complete guidelines and checklist +- [Contributing](CONTRIBUTING.md) – Contribution requirements +- [PR Template](docs/pull_request_template.md) – Pull request checklist +- [Windows App SDK Docs](https://docs.microsoft.com/windows/apps/windows-app-sdk/) – Official documentation diff --git a/README.md b/README.md index db6a2db1c..bc82a6b70 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,11 @@ -# Windows App SDK Samples +<p align="center"> + <a href="https://aka.ms/winappsdk"> + <img src="./docs/images/header.png" alt="Windows App SDK Banner" /> + </a> +</p> -This repository hosts samples for the [Windows App SDK](https://github.com/microsoft/WindowsAppSDK). Samples for various features shipping in the Windows App SDK will be added to this repository. For more information about the Windows App SDK, visit the [Windows App SDK Documentation](https://docs.microsoft.com/windows/apps/windows-app-sdk/). To learn more about the Windows App SDK design or to contribute to the project, make feature proposals, or start discussions, visit the [Windows App SDK GitHub page](https://github.com/microsoft/WindowsAppSDK). +<h1 align="center">Windows App SDK samples</h1> -## List of samples This repository hosts samples for the [Windows App SDK](https://github.com/microsoft/WindowsAppSDK). Samples for various features shipping in the Windows App SDK will be added to this repository. For more information about the Windows App SDK, visit the [Windows App SDK documentation](https://docs.microsoft.com/windows/apps/windows-app-sdk/). To learn more about the Windows App SDK design or to contribute to the project, make feature proposals, or start discussions, visit the [Windows App SDK GitHub page](https://github.com/microsoft/WindowsAppSDK). @@ -30,28 +33,33 @@ This repository hosts samples for the [Windows App SDK](https://github.com/micro #### Data and Files - [Resource Management](Samples/ResourceManagement): These samples demonstrates app resource management using the MRT Core APIs. -#### Deployment +### Deployment - [Deployment Manager](Samples/DeploymentManager): This sample demonstrates how to initialize and access deployment information for the Windows App SDK runtime. - [Installer](Samples/Installer): This sample demonstrates how to launch the Windows App SDK installer without a console window. - [Unpackaged](Samples/Unpackaged): These samples demonstrate auto-initialization with the Windows App SDK package from non-MSIX (unpackaged) application. -#### Dynamic Dependencies +### Dynamic Dependencies - [DirectX](DynamicDependenciesSample/DynamicDependencies): This sample demonstrates how to use the Dynamic Dependencies API to dynamically load the DirectX Runtime MSIX framework package. -#### Graphics +### Graphics +- [Mica](Samples/Mica): These samples demonstrate how to use the Mica material in different apps and frameworks. - [Text Rendering](Samples/TextRendering): This sample is a gallery of the DWriteCore APIs demonstrating text rendering. -#### Notifications +### Islands +- [Islands](Samples/Islands): This sample shows how to add a WinAppSDK island with Xaml content to a Win32 app. + +### Notifications - [Push Notifications](Samples/Notifications/Push): This is a sample app that showcases Push Notifications. - [App Notifications](Samples/Notifications/App): This is a sample app that showcases App Notifications. -#### Runtime Components +### Runtime Components - [Custom Controls](Samples/CustomControls): This sample shows how to author a Windows Runtime Component in C# with custom WinUI controls. -#### User Interface and Input +### User Interface and Input + - [Windowing](Samples/Windowing): This sample demonstrates how to manage app windows using the Windowing APIs. -- [Windows Input and Composition Gallery](https://github.com/microsoft/WindowsCompositionSamples): This collection of samples showcases Microsoft.UI.Composition and Microsoft.UI.Input APIs. -- [WinUI 3 Gallery](https://github.com/microsoft/WinUI-Gallery/): This is a sample app that showcases all of the WinUI 3 controls in action. +- [Windows Composition, Input and SceneGraph](Samples/SceneGraph): This collection of samples showcases Microsoft.UI.Composition, Microsoft.UI.Input and SceneGraph APIs. +- [WinUI 3 Gallery](https://github.com/microsoft/WinUI-Gallery): This is a sample app that showcases all of the WinUI 3 controls in action. ### Widgets - [Widgets](Samples/Widgets): These samples demonstrate how to author Windows Widgets with the Windows App SDK. @@ -64,38 +72,38 @@ Thes Windows App SDK samples have the following system requirements: - [Visual Studio 2022](https://visualstudio.microsoft.com/downloads/) or Visual Studio 2019 version 16.9 or later, with the following workloads and components: - - Universal Windows Platform development + - Windows application development - .NET Desktop Development (needed even if you're only building C++ Win32 apps) - Desktop development with C++ (needed even if you're only building .NET apps) - Windows SDK version 2004 (build 19041) or later. This is installed with Visual Studio by default. -- Building .NET C# samples with Windows App SDK 1.1 also requires one of the following .NET SDK versions or later: - - 6.0.202 - - 6.0.104 - - 5.0.407 - - 5.0.213 - Refer to the docs on [system requirements](https://docs.microsoft.com/windows/apps/windows-app-sdk/system-requirements) and [tools for Windows app development](https://docs.microsoft.com/windows/apps/windows-app-sdk/set-up-your-development-environment) for a detalied list of requirements for developing apps with the Windows App SDK. -## Using the samples +## 🚀 Using the samples To use the samples with Git, clone the WindowsAppSDK-Samples repository by running `git clone https://github.com/microsoft/WindowsAppSDK-Samples.git` from a command prompt. You can then navigate to the directory of a sample and open the solution file in Visual Studio. The easiest way to use these samples without Git is to download the ZIP file. Select *Download ZIP* from the download dropdown, unzip the entire archive and open the samples in Visual Studio. -### Samples versioning +## 📄 Samples versioning The samples will be updated with GA releases of the Windows App SDK. The `main` branch includes the latest samples, which may also include experimental or preview features. Specific release branches are named `release/x.y` and contain samples that reference the corresponding GA version of the Windows App SDK. This repository currently includes the following release branches: +- [release/experimental](https://github.com/microsoft/WindowsAppSDK-Samples/tree/release/experimental) +- [release/1.8](https://github.com/microsoft/WindowsAppSDK-Samples/tree/release/1.8-stable) +- [release/1.7](https://github.com/microsoft/WindowsAppSDK-Samples/tree/release/1.7-stable) +- [release/1.6](https://github.com/microsoft/WindowsAppSDK-Samples/tree/release/1.6-stable) +- [release/1.5](https://github.com/microsoft/WindowsAppSDK-Samples/tree/release/1.5-stable) +- [release/1.1](https://github.com/microsoft/WindowsAppSDK-Samples/tree/release/1.1) - [release/1.0](https://github.com/microsoft/WindowsAppSDK-Samples/tree/release/1.0) - [release/0.8](https://github.com/microsoft/WindowsAppSDK-Samples/tree/release/0.8) - [release/0.5](https://github.com/microsoft/WindowsAppSDK-Samples/tree/release/0.5) -## Contributing +## 🏆 Contributing These samples are provided by feature teams and we welcome your input on issues and suggestions for new samples. We encourage you to [file a new issue](https://github.com/microsoft/WindowsAppSDK-Samples/issues/new) for any feedback or questions! -Sample authors should follow the [samples guidelines](docs/samples-guidelines.md) to begin developing their samples. For WinUI-based Windows App SDK samples, use the [sample templates](Templates/README.md). The VSIX file is available for download in the Github releases page [here](https://github.com/microsoft/WindowsAppSDK-Samples/releases). +Sample authors should follow the [samples guidelines](docs/samples-guidelines.md) to begin developing their samples. For WinUI-based Windows App SDK samples, use the [sample templates](Templates/README.md). The VSIX file is available for download in the GitHub releases page [here](https://github.com/microsoft/WindowsAppSDK-Samples/releases). This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information, see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments. diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/App.xaml b/Samples/WinUI/ConditionalPredicate/cpp-winui/App.xaml new file mode 100644 index 000000000..4b0f0bd3f --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/App.xaml @@ -0,0 +1,21 @@ +<!-- Copyright (c) Microsoft Corporation. + Licensed under the MIT License. --> +<Application + x:Class="ConditionalXamlPredicate.App" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:local="using:ConditionalXamlPredicate"> + + <Application.Resources> + <!-- Application-specific resources --> + <ResourceDictionary> + <ResourceDictionary.MergedDictionaries> + <!-- + Styles that define common aspects of the platform look and feel + Required by Visual Studio project and item templates + --> + <ResourceDictionary Source="ms-appx:///Styles.xaml"/> + </ResourceDictionary.MergedDictionaries> + </ResourceDictionary> + </Application.Resources> +</Application> diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/App.xaml.cpp b/Samples/WinUI/ConditionalPredicate/cpp-winui/App.xaml.cpp new file mode 100644 index 000000000..9f809deba --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/App.xaml.cpp @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "pch.h" + +#include "App.xaml.h" +#include "MainWindow.xaml.h" + +namespace winrt +{ + using namespace Windows::Foundation; + using namespace Microsoft::UI::Xaml; +} + +namespace winrt::ConditionalXamlPredicate::implementation +{ + App::App() + { + InitializeComponent(); + +#if defined _DEBUG && !defined DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION + UnhandledException([](winrt::IInspectable const&, winrt::UnhandledExceptionEventArgs const& e) + { + if (IsDebuggerPresent()) + { + auto errorMessage = e.Message(); + __debugbreak(); + } + }); +#endif + } + + void App::OnLaunched(winrt::LaunchActivatedEventArgs const&) + { + window = winrt::make<MainWindow>(); + window.Activate(); + } +} diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/App.xaml.h b/Samples/WinUI/ConditionalPredicate/cpp-winui/App.xaml.h new file mode 100644 index 000000000..eb9add034 --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/App.xaml.h @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once +#include "App.xaml.g.h" +#include "pch.h" + +namespace winrt::ConditionalXamlPredicate::implementation +{ + struct App : AppT<App> + { + App(); + + void OnLaunched(Microsoft::UI::Xaml::LaunchActivatedEventArgs const&); + + private: + Microsoft::UI::Xaml::Window window{ nullptr }; + }; +} diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/Assets/SplashScreen.png b/Samples/WinUI/ConditionalPredicate/cpp-winui/Assets/SplashScreen.png new file mode 100644 index 000000000..184821318 Binary files /dev/null and b/Samples/WinUI/ConditionalPredicate/cpp-winui/Assets/SplashScreen.png differ diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/Assets/Square150x150Logo.png b/Samples/WinUI/ConditionalPredicate/cpp-winui/Assets/Square150x150Logo.png new file mode 100644 index 000000000..a50c70379 Binary files /dev/null and b/Samples/WinUI/ConditionalPredicate/cpp-winui/Assets/Square150x150Logo.png differ diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/Assets/Square44x44Logo.png b/Samples/WinUI/ConditionalPredicate/cpp-winui/Assets/Square44x44Logo.png new file mode 100644 index 000000000..844b60c20 Binary files /dev/null and b/Samples/WinUI/ConditionalPredicate/cpp-winui/Assets/Square44x44Logo.png differ diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/Assets/Wide310x150Logo.png b/Samples/WinUI/ConditionalPredicate/cpp-winui/Assets/Wide310x150Logo.png new file mode 100644 index 000000000..b5d5f2c42 Binary files /dev/null and b/Samples/WinUI/ConditionalPredicate/cpp-winui/Assets/Wide310x150Logo.png differ diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/Assets/logo.png b/Samples/WinUI/ConditionalPredicate/cpp-winui/Assets/logo.png new file mode 100644 index 000000000..fd2293e7b Binary files /dev/null and b/Samples/WinUI/ConditionalPredicate/cpp-winui/Assets/logo.png differ diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/Assets/windows-sdk.ico b/Samples/WinUI/ConditionalPredicate/cpp-winui/Assets/windows-sdk.ico new file mode 100644 index 000000000..3ad20c7c2 Binary files /dev/null and b/Samples/WinUI/ConditionalPredicate/cpp-winui/Assets/windows-sdk.ico differ diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/ConditionalXamlPredicate.sln b/Samples/WinUI/ConditionalPredicate/cpp-winui/ConditionalXamlPredicate.sln new file mode 100644 index 000000000..d29f2b3ba --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/ConditionalXamlPredicate.sln @@ -0,0 +1,43 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.14.36811.4 d17.14 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ConditionalXamlPredicate", "ConditionalXamlPredicate.vcxproj", "{E5E59AF9-6F16-4D82-9C7B-AF97DB681432}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|arm64 = Debug|arm64 + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|arm64 = Release|arm64 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E5E59AF9-6F16-4D82-9C7B-AF97DB681432}.Debug|arm64.ActiveCfg = Debug|arm64 + {E5E59AF9-6F16-4D82-9C7B-AF97DB681432}.Debug|arm64.Build.0 = Debug|arm64 + {E5E59AF9-6F16-4D82-9C7B-AF97DB681432}.Debug|arm64.Deploy.0 = Debug|arm64 + {E5E59AF9-6F16-4D82-9C7B-AF97DB681432}.Debug|x64.ActiveCfg = Debug|x64 + {E5E59AF9-6F16-4D82-9C7B-AF97DB681432}.Debug|x64.Build.0 = Debug|x64 + {E5E59AF9-6F16-4D82-9C7B-AF97DB681432}.Debug|x64.Deploy.0 = Debug|x64 + {E5E59AF9-6F16-4D82-9C7B-AF97DB681432}.Debug|x86.ActiveCfg = Debug|Win32 + {E5E59AF9-6F16-4D82-9C7B-AF97DB681432}.Debug|x86.Build.0 = Debug|Win32 + {E5E59AF9-6F16-4D82-9C7B-AF97DB681432}.Debug|x86.Deploy.0 = Debug|Win32 + {E5E59AF9-6F16-4D82-9C7B-AF97DB681432}.Release|arm64.ActiveCfg = Release|arm64 + {E5E59AF9-6F16-4D82-9C7B-AF97DB681432}.Release|arm64.Build.0 = Release|arm64 + {E5E59AF9-6F16-4D82-9C7B-AF97DB681432}.Release|arm64.Deploy.0 = Release|arm64 + {E5E59AF9-6F16-4D82-9C7B-AF97DB681432}.Release|x64.ActiveCfg = Release|x64 + {E5E59AF9-6F16-4D82-9C7B-AF97DB681432}.Release|x64.Build.0 = Release|x64 + {E5E59AF9-6F16-4D82-9C7B-AF97DB681432}.Release|x64.Deploy.0 = Release|x64 + {E5E59AF9-6F16-4D82-9C7B-AF97DB681432}.Release|x86.ActiveCfg = Release|Win32 + {E5E59AF9-6F16-4D82-9C7B-AF97DB681432}.Release|x86.Build.0 = Release|Win32 + {E5E59AF9-6F16-4D82-9C7B-AF97DB681432}.Release|x86.Deploy.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A3F7F7C0-FD0C-4383-9341-D8E5A148B18E} + EndGlobalSection +EndGlobal diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/ConditionalXamlPredicate.vcxproj b/Samples/WinUI/ConditionalPredicate/cpp-winui/ConditionalXamlPredicate.vcxproj new file mode 100644 index 000000000..fdf0b029a --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/ConditionalXamlPredicate.vcxproj @@ -0,0 +1,260 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="packages\Microsoft.WindowsAppSDK.2.0.0-experimental4\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('packages\Microsoft.WindowsAppSDK.2.0.0-experimental4\build\native\Microsoft.WindowsAppSDK.props')" /> + <Import Project="packages\Microsoft.WindowsAppSDK.WinUI.2.0.4-experimental\build\native\Microsoft.WindowsAppSDK.WinUI.props" Condition="Exists('packages\Microsoft.WindowsAppSDK.WinUI.2.0.4-experimental\build\native\Microsoft.WindowsAppSDK.WinUI.props')" /> + <Import Project="packages\Microsoft.WindowsAppSDK.Widgets.2.0.3-experimental\build\native\Microsoft.WindowsAppSDK.Widgets.props" Condition="Exists('packages\Microsoft.WindowsAppSDK.Widgets.2.0.3-experimental\build\native\Microsoft.WindowsAppSDK.Widgets.props')" /> + <Import Project="packages\Microsoft.WindowsAppSDK.Runtime.2.0.0-experimental4\build\native\Microsoft.WindowsAppSDK.Runtime.props" Condition="Exists('packages\Microsoft.WindowsAppSDK.Runtime.2.0.0-experimental4\build\native\Microsoft.WindowsAppSDK.Runtime.props')" /> + <Import Project="packages\Microsoft.WindowsAppSDK.ML.2.0.169-experimental\build\native\Microsoft.WindowsAppSDK.ML.props" Condition="Exists('packages\Microsoft.WindowsAppSDK.ML.2.0.169-experimental\build\native\Microsoft.WindowsAppSDK.ML.props')" /> + <Import Project="packages\Microsoft.WindowsAppSDK.AI.2.0.130-experimental\build\native\Microsoft.WindowsAppSDK.AI.props" Condition="Exists('packages\Microsoft.WindowsAppSDK.AI.2.0.130-experimental\build\native\Microsoft.WindowsAppSDK.AI.props')" /> + <Import Project="packages\Microsoft.WindowsAppSDK.Foundation.2.0.11-experimental\build\native\Microsoft.WindowsAppSDK.Foundation.props" Condition="Exists('packages\Microsoft.WindowsAppSDK.Foundation.2.0.11-experimental\build\native\Microsoft.WindowsAppSDK.Foundation.props')" /> + <Import Project="packages\Microsoft.WindowsAppSDK.InteractiveExperiences.2.0.5-experimental\build\native\Microsoft.WindowsAppSDK.InteractiveExperiences.props" Condition="Exists('packages\Microsoft.WindowsAppSDK.InteractiveExperiences.2.0.5-experimental\build\native\Microsoft.WindowsAppSDK.InteractiveExperiences.props')" /> + <Import Project="packages\Microsoft.WindowsAppSDK.DWrite.2.0.1-experimental\build\Microsoft.WindowsAppSDK.DWrite.props" Condition="Exists('packages\Microsoft.WindowsAppSDK.DWrite.2.0.1-experimental\build\Microsoft.WindowsAppSDK.DWrite.props')" /> + <Import Project="packages\Microsoft.WindowsAppSDK.Base.2.0.1-experimental\build\native\Microsoft.WindowsAppSDK.Base.props" Condition="Exists('packages\Microsoft.WindowsAppSDK.Base.2.0.1-experimental\build\native\Microsoft.WindowsAppSDK.Base.props')" /> + <Import Project="packages\Microsoft.Windows.SDK.BuildTools.MSIX.1.7.20250829.1\build\Microsoft.Windows.SDK.BuildTools.MSIX.props" Condition="Exists('packages\Microsoft.Windows.SDK.BuildTools.MSIX.1.7.20250829.1\build\Microsoft.Windows.SDK.BuildTools.MSIX.props')" /> + <Import Project="packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.4654\build\Microsoft.Windows.SDK.BuildTools.props" Condition="Exists('packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.4654\build\Microsoft.Windows.SDK.BuildTools.props')" /> + <Import Project="packages\Microsoft.Windows.CppWinRT.2.0.210922.5\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('packages\Microsoft.Windows.CppWinRT.2.0.210922.5\build\native\Microsoft.Windows.CppWinRT.props')" /> + <PropertyGroup Label="Globals"> + <CppWinRTOptimized>true</CppWinRTOptimized> + <CppWinRTRootNamespaceAutoMerge>true</CppWinRTRootNamespaceAutoMerge> + <MinimalCoreWin>true</MinimalCoreWin> + <ProjectGuid>{e5e59af9-6f16-4d82-9c7b-af97db681432}</ProjectGuid> + <ProjectName>ConditionalXamlPredicate</ProjectName> + <RootNamespace>ConditionalXamlPredicate</RootNamespace> + <!-- + $(TargetName) should be same as $(RootNamespace) so that the produced binaries (.exe/.pri/etc.) + have a name that matches the .winmd + --> + <TargetName>$(RootNamespace)</TargetName> + <DefaultLanguage>en-US</DefaultLanguage> + <MinimumVisualStudioVersion>16.0</MinimumVisualStudioVersion> + <AppContainerApplication>false</AppContainerApplication> + <AppxPackage>true</AppxPackage> + <ApplicationType>Windows Store</ApplicationType> + <ApplicationTypeRevision>10.0</ApplicationTypeRevision> + <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> + <WindowsTargetPlatformMinVersion>10.0.19041.0</WindowsTargetPlatformMinVersion> + <UseWinUI>true</UseWinUI> + <EnablePreviewMsixTooling>true</EnablePreviewMsixTooling> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|arm64"> + <Configuration>Debug</Configuration> + <Platform>arm64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|arm64"> + <Configuration>Release</Configuration> + <Platform>arm64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <PlatformToolset>v143</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + <DesktopCompatible>true</DesktopCompatible> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration"> + <UseDebugLibraries>true</UseDebugLibraries> + <LinkIncremental>true</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration"> + <UseDebugLibraries>false</UseDebugLibraries> + <WholeProgramOptimization>true</WholeProgramOptimization> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ItemDefinitionGroup> + <ClCompile> + <PrecompiledHeader>Use</PrecompiledHeader> + <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> + <PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile> + <WarningLevel>Level4</WarningLevel> + <AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'"> + <ClCompile> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)'=='Release'"> + <ClCompile> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <Manifest Include="app.manifest" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="MainPage.xaml.h"> + <DependentUpon>MainPage.xaml</DependentUpon> + <SubType>Code</SubType> + </ClInclude> + <ClInclude Include="MyCustomPredicate.h" /> + <ClInclude Include="pch.h" /> + <ClInclude Include="App.xaml.h"> + <DependentUpon>App.xaml</DependentUpon> + </ClInclude> + <ClInclude Include="MainWindow.xaml.h"> + <DependentUpon>MainWindow.xaml</DependentUpon> + </ClInclude> + <ClInclude Include="SampleConfiguration.h" /> + <ClInclude Include="Scenario1_LoadConditionalControls.xaml.h"> + <DependentUpon>Scenario1_LoadConditionalControls.xaml</DependentUpon> + <SubType>Code</SubType> + </ClInclude> + <ClInclude Include="Scenario2_ConditionalArguments.xaml.h"> + <DependentUpon>Scenario2_ConditionalArguments.xaml</DependentUpon> + <SubType>Code</SubType> + </ClInclude> + <ClInclude Include="SettingsPage.xaml.h"> + <DependentUpon>SettingsPage.xaml</DependentUpon> + <SubType>Code</SubType> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ApplicationDefinition Include="App.xaml" /> + <Page Include="MainPage.xaml"> + <SubType>Designer</SubType> + </Page> + <Page Include="MainWindow.xaml" /> + <Page Include="Scenario1_LoadConditionalControls.xaml"> + <SubType>Designer</SubType> + </Page> + <Page Include="Scenario2_ConditionalArguments.xaml"> + <SubType>Designer</SubType> + </Page> + <Page Include="SettingsPage.xaml"> + <SubType>Designer</SubType> + </Page> + <Page Include="Styles.xaml"> + <SubType>Designer</SubType> + </Page> + </ItemGroup> + <ItemGroup> + <ClCompile Include="MainPage.xaml.cpp"> + <DependentUpon>MainPage.xaml</DependentUpon> + <SubType>Code</SubType> + </ClCompile> + <ClCompile Include="MyCustomPredicate.cpp" /> + <ClCompile Include="pch.cpp"> + <PrecompiledHeader>Create</PrecompiledHeader> + </ClCompile> + <ClCompile Include="App.xaml.cpp"> + <DependentUpon>App.xaml</DependentUpon> + </ClCompile> + <ClCompile Include="MainWindow.xaml.cpp"> + <DependentUpon>MainWindow.xaml</DependentUpon> + </ClCompile> + <ClCompile Include="$(GeneratedFilesDir)module.g.cpp" /> + <ClCompile Include="SampleConfiguration.cpp" /> + <ClCompile Include="Scenario1_LoadConditionalControls.xaml.cpp"> + <DependentUpon>Scenario1_LoadConditionalControls.xaml</DependentUpon> + <SubType>Code</SubType> + </ClCompile> + <ClCompile Include="Scenario2_ConditionalArguments.xaml.cpp"> + <DependentUpon>Scenario2_ConditionalArguments.xaml</DependentUpon> + <SubType>Code</SubType> + </ClCompile> + <ClCompile Include="SettingsPage.xaml.cpp"> + <DependentUpon>SettingsPage.xaml</DependentUpon> + <SubType>Code</SubType> + </ClCompile> + </ItemGroup> + <ItemGroup> + <Midl Include="Project.idl"> + <SubType>Code</SubType> + </Midl> + </ItemGroup> + <ItemGroup> + <Image Include="Assets\SplashScreen.png" /> + <Image Include="Assets\Square150x150Logo.png" /> + <Image Include="Assets\Square44x44Logo.png" /> + <Image Include="Assets\Wide310x150Logo.png" /> + <Image Include="Assets\logo.png" /> + <Image Include="Assets\windows-sdk.ico" /> + </ItemGroup> + <!-- Defining the "Msix" ProjectCapability here allows the Single-project MSIX Packaging + Tools extension to be activated for this project even if the Windows App SDK Nuget + package has not yet been restored --> + <ItemGroup Condition="'$(DisableMsixProjectCapabilityAddedByProject)'!='true' and '$(EnablePreviewMsixTooling)'=='true'"> + <ProjectCapability Include="Msix" /> + </ItemGroup> + <ItemGroup> + <None Include="packages.config" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + <Import Project="packages\Microsoft.Windows.CppWinRT.2.0.210922.5\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('packages\Microsoft.Windows.CppWinRT.2.0.210922.5\build\native\Microsoft.Windows.CppWinRT.targets')" /> + <Import Project="packages\Microsoft.Web.WebView2.1.0.3405.78\build\native\Microsoft.Web.WebView2.targets" Condition="Exists('packages\Microsoft.Web.WebView2.1.0.3405.78\build\native\Microsoft.Web.WebView2.targets')" /> + <Import Project="packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.4654\build\Microsoft.Windows.SDK.BuildTools.targets" Condition="Exists('packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.4654\build\Microsoft.Windows.SDK.BuildTools.targets')" /> + <Import Project="packages\Microsoft.Windows.SDK.BuildTools.MSIX.1.7.20250829.1\build\Microsoft.Windows.SDK.BuildTools.MSIX.targets" Condition="Exists('packages\Microsoft.Windows.SDK.BuildTools.MSIX.1.7.20250829.1\build\Microsoft.Windows.SDK.BuildTools.MSIX.targets')" /> + <Import Project="packages\Microsoft.WindowsAppSDK.Base.2.0.1-experimental\build\native\Microsoft.WindowsAppSDK.Base.targets" Condition="Exists('packages\Microsoft.WindowsAppSDK.Base.2.0.1-experimental\build\native\Microsoft.WindowsAppSDK.Base.targets')" /> + <Import Project="packages\Microsoft.WindowsAppSDK.DWrite.2.0.1-experimental\build\Microsoft.WindowsAppSDK.DWrite.targets" Condition="Exists('packages\Microsoft.WindowsAppSDK.DWrite.2.0.1-experimental\build\Microsoft.WindowsAppSDK.DWrite.targets')" /> + <Import Project="packages\Microsoft.WindowsAppSDK.InteractiveExperiences.2.0.5-experimental\build\native\Microsoft.WindowsAppSDK.InteractiveExperiences.targets" Condition="Exists('packages\Microsoft.WindowsAppSDK.InteractiveExperiences.2.0.5-experimental\build\native\Microsoft.WindowsAppSDK.InteractiveExperiences.targets')" /> + <Import Project="packages\Microsoft.WindowsAppSDK.Foundation.2.0.11-experimental\build\native\Microsoft.WindowsAppSDK.Foundation.targets" Condition="Exists('packages\Microsoft.WindowsAppSDK.Foundation.2.0.11-experimental\build\native\Microsoft.WindowsAppSDK.Foundation.targets')" /> + <Import Project="packages\Microsoft.WindowsAppSDK.AI.2.0.130-experimental\build\native\Microsoft.WindowsAppSDK.AI.targets" Condition="Exists('packages\Microsoft.WindowsAppSDK.AI.2.0.130-experimental\build\native\Microsoft.WindowsAppSDK.AI.targets')" /> + <Import Project="packages\Microsoft.WindowsAppSDK.ML.2.0.169-experimental\build\native\Microsoft.WindowsAppSDK.ML.targets" Condition="Exists('packages\Microsoft.WindowsAppSDK.ML.2.0.169-experimental\build\native\Microsoft.WindowsAppSDK.ML.targets')" /> + <Import Project="packages\Microsoft.WindowsAppSDK.Runtime.2.0.0-experimental4\build\native\Microsoft.WindowsAppSDK.Runtime.targets" Condition="Exists('packages\Microsoft.WindowsAppSDK.Runtime.2.0.0-experimental4\build\native\Microsoft.WindowsAppSDK.Runtime.targets')" /> + <Import Project="packages\Microsoft.WindowsAppSDK.Widgets.2.0.3-experimental\build\native\Microsoft.WindowsAppSDK.Widgets.targets" Condition="Exists('packages\Microsoft.WindowsAppSDK.Widgets.2.0.3-experimental\build\native\Microsoft.WindowsAppSDK.Widgets.targets')" /> + <Import Project="packages\Microsoft.WindowsAppSDK.WinUI.2.0.4-experimental\build\native\Microsoft.WindowsAppSDK.WinUI.targets" Condition="Exists('packages\Microsoft.WindowsAppSDK.WinUI.2.0.4-experimental\build\native\Microsoft.WindowsAppSDK.WinUI.targets')" /> + <Import Project="packages\Microsoft.WindowsAppSDK.2.0.0-experimental4\build\native\Microsoft.WindowsAppSDK.targets" Condition="Exists('packages\Microsoft.WindowsAppSDK.2.0.0-experimental4\build\native\Microsoft.WindowsAppSDK.targets')" /> + </ImportGroup> + <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> + <PropertyGroup> + <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText> + </PropertyGroup> + <Error Condition="!Exists('packages\Microsoft.Windows.CppWinRT.2.0.210922.5\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.Windows.CppWinRT.2.0.210922.5\build\native\Microsoft.Windows.CppWinRT.props'))" /> + <Error Condition="!Exists('packages\Microsoft.Windows.CppWinRT.2.0.210922.5\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.Windows.CppWinRT.2.0.210922.5\build\native\Microsoft.Windows.CppWinRT.targets'))" /> + <Error Condition="!Exists('packages\Microsoft.Web.WebView2.1.0.3405.78\build\native\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.Web.WebView2.1.0.3405.78\build\native\Microsoft.Web.WebView2.targets'))" /> + <Error Condition="!Exists('packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.4654\build\Microsoft.Windows.SDK.BuildTools.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.4654\build\Microsoft.Windows.SDK.BuildTools.props'))" /> + <Error Condition="!Exists('packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.4654\build\Microsoft.Windows.SDK.BuildTools.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.4654\build\Microsoft.Windows.SDK.BuildTools.targets'))" /> + <Error Condition="!Exists('packages\Microsoft.Windows.SDK.BuildTools.MSIX.1.7.20250829.1\build\Microsoft.Windows.SDK.BuildTools.MSIX.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.Windows.SDK.BuildTools.MSIX.1.7.20250829.1\build\Microsoft.Windows.SDK.BuildTools.MSIX.props'))" /> + <Error Condition="!Exists('packages\Microsoft.Windows.SDK.BuildTools.MSIX.1.7.20250829.1\build\Microsoft.Windows.SDK.BuildTools.MSIX.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.Windows.SDK.BuildTools.MSIX.1.7.20250829.1\build\Microsoft.Windows.SDK.BuildTools.MSIX.targets'))" /> + <Error Condition="!Exists('packages\Microsoft.WindowsAppSDK.Base.2.0.1-experimental\build\native\Microsoft.WindowsAppSDK.Base.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.WindowsAppSDK.Base.2.0.1-experimental\build\native\Microsoft.WindowsAppSDK.Base.props'))" /> + <Error Condition="!Exists('packages\Microsoft.WindowsAppSDK.Base.2.0.1-experimental\build\native\Microsoft.WindowsAppSDK.Base.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.WindowsAppSDK.Base.2.0.1-experimental\build\native\Microsoft.WindowsAppSDK.Base.targets'))" /> + <Error Condition="!Exists('packages\Microsoft.WindowsAppSDK.DWrite.2.0.1-experimental\build\Microsoft.WindowsAppSDK.DWrite.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.WindowsAppSDK.DWrite.2.0.1-experimental\build\Microsoft.WindowsAppSDK.DWrite.props'))" /> + <Error Condition="!Exists('packages\Microsoft.WindowsAppSDK.DWrite.2.0.1-experimental\build\Microsoft.WindowsAppSDK.DWrite.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.WindowsAppSDK.DWrite.2.0.1-experimental\build\Microsoft.WindowsAppSDK.DWrite.targets'))" /> + <Error Condition="!Exists('packages\Microsoft.WindowsAppSDK.InteractiveExperiences.2.0.5-experimental\build\native\Microsoft.WindowsAppSDK.InteractiveExperiences.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.WindowsAppSDK.InteractiveExperiences.2.0.5-experimental\build\native\Microsoft.WindowsAppSDK.InteractiveExperiences.props'))" /> + <Error Condition="!Exists('packages\Microsoft.WindowsAppSDK.InteractiveExperiences.2.0.5-experimental\build\native\Microsoft.WindowsAppSDK.InteractiveExperiences.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.WindowsAppSDK.InteractiveExperiences.2.0.5-experimental\build\native\Microsoft.WindowsAppSDK.InteractiveExperiences.targets'))" /> + <Error Condition="!Exists('packages\Microsoft.WindowsAppSDK.Foundation.2.0.11-experimental\build\native\Microsoft.WindowsAppSDK.Foundation.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.WindowsAppSDK.Foundation.2.0.11-experimental\build\native\Microsoft.WindowsAppSDK.Foundation.props'))" /> + <Error Condition="!Exists('packages\Microsoft.WindowsAppSDK.Foundation.2.0.11-experimental\build\native\Microsoft.WindowsAppSDK.Foundation.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.WindowsAppSDK.Foundation.2.0.11-experimental\build\native\Microsoft.WindowsAppSDK.Foundation.targets'))" /> + <Error Condition="!Exists('packages\Microsoft.WindowsAppSDK.AI.2.0.130-experimental\build\native\Microsoft.WindowsAppSDK.AI.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.WindowsAppSDK.AI.2.0.130-experimental\build\native\Microsoft.WindowsAppSDK.AI.props'))" /> + <Error Condition="!Exists('packages\Microsoft.WindowsAppSDK.AI.2.0.130-experimental\build\native\Microsoft.WindowsAppSDK.AI.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.WindowsAppSDK.AI.2.0.130-experimental\build\native\Microsoft.WindowsAppSDK.AI.targets'))" /> + <Error Condition="!Exists('packages\Microsoft.WindowsAppSDK.ML.2.0.169-experimental\build\native\Microsoft.WindowsAppSDK.ML.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.WindowsAppSDK.ML.2.0.169-experimental\build\native\Microsoft.WindowsAppSDK.ML.props'))" /> + <Error Condition="!Exists('packages\Microsoft.WindowsAppSDK.ML.2.0.169-experimental\build\native\Microsoft.WindowsAppSDK.ML.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.WindowsAppSDK.ML.2.0.169-experimental\build\native\Microsoft.WindowsAppSDK.ML.targets'))" /> + <Error Condition="!Exists('packages\Microsoft.WindowsAppSDK.Runtime.2.0.0-experimental4\build\native\Microsoft.WindowsAppSDK.Runtime.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.WindowsAppSDK.Runtime.2.0.0-experimental4\build\native\Microsoft.WindowsAppSDK.Runtime.props'))" /> + <Error Condition="!Exists('packages\Microsoft.WindowsAppSDK.Runtime.2.0.0-experimental4\build\native\Microsoft.WindowsAppSDK.Runtime.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.WindowsAppSDK.Runtime.2.0.0-experimental4\build\native\Microsoft.WindowsAppSDK.Runtime.targets'))" /> + <Error Condition="!Exists('packages\Microsoft.WindowsAppSDK.Widgets.2.0.3-experimental\build\native\Microsoft.WindowsAppSDK.Widgets.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.WindowsAppSDK.Widgets.2.0.3-experimental\build\native\Microsoft.WindowsAppSDK.Widgets.props'))" /> + <Error Condition="!Exists('packages\Microsoft.WindowsAppSDK.Widgets.2.0.3-experimental\build\native\Microsoft.WindowsAppSDK.Widgets.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.WindowsAppSDK.Widgets.2.0.3-experimental\build\native\Microsoft.WindowsAppSDK.Widgets.targets'))" /> + <Error Condition="!Exists('packages\Microsoft.WindowsAppSDK.WinUI.2.0.4-experimental\build\native\Microsoft.WindowsAppSDK.WinUI.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.WindowsAppSDK.WinUI.2.0.4-experimental\build\native\Microsoft.WindowsAppSDK.WinUI.props'))" /> + <Error Condition="!Exists('packages\Microsoft.WindowsAppSDK.WinUI.2.0.4-experimental\build\native\Microsoft.WindowsAppSDK.WinUI.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.WindowsAppSDK.WinUI.2.0.4-experimental\build\native\Microsoft.WindowsAppSDK.WinUI.targets'))" /> + <Error Condition="!Exists('packages\Microsoft.WindowsAppSDK.2.0.0-experimental4\build\native\Microsoft.WindowsAppSDK.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.WindowsAppSDK.2.0.0-experimental4\build\native\Microsoft.WindowsAppSDK.props'))" /> + <Error Condition="!Exists('packages\Microsoft.WindowsAppSDK.2.0.0-experimental4\build\native\Microsoft.WindowsAppSDK.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.WindowsAppSDK.2.0.0-experimental4\build\native\Microsoft.WindowsAppSDK.targets'))" /> + </Target> +</Project> \ No newline at end of file diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/ConditionalXamlPredicate.vcxproj.filters b/Samples/WinUI/ConditionalPredicate/cpp-winui/ConditionalXamlPredicate.vcxproj.filters new file mode 100644 index 000000000..a034c65c9 --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/ConditionalXamlPredicate.vcxproj.filters @@ -0,0 +1,62 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <ApplicationDefinition Include="App.xaml" /> + </ItemGroup> + <ItemGroup> + <Page Include="MainWindow.xaml" /> + <Page Include="MainPage.xaml" /> + <Page Include="SettingsPage.xaml" /> + <Page Include="Scenario1_LoadConditionalControls.xaml" /> + <Page Include="Styles.xaml" /> + <Page Include="Scenario2_ConditionalArguments.xaml" /> + </ItemGroup> + <ItemGroup> + <Midl Include="Project.idl" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="pch.cpp" /> + <ClCompile Include="$(GeneratedFilesDir)module.g.cpp" /> + <ClCompile Include="SampleConfiguration.cpp" /> + <ClCompile Include="MyCustomPredicate.cpp" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="pch.h" /> + <ClInclude Include="SampleConfiguration.h" /> + <ClInclude Include="MyCustomPredicate.h" /> + </ItemGroup> + <ItemGroup> + <Image Include="Assets\Wide310x150Logo.png"> + <Filter>Assets</Filter> + </Image> + <Image Include="Assets\logo.png"> + <Filter>Assets</Filter> + </Image> + <Image Include="Assets\Square150x150Logo.png"> + <Filter>Assets</Filter> + </Image> + <Image Include="Assets\Square44x44Logo.png"> + <Filter>Assets</Filter> + </Image> + <Image Include="Assets\SplashScreen.png"> + <Filter>Assets</Filter> + </Image> + <Image Include="Assets\windows-sdk.ico"> + <Filter>Assets</Filter> + </Image> + </ItemGroup> + <ItemGroup> + <Filter Include="Assets"> + <UniqueIdentifier>{$guid1}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <Manifest Include="app.manifest" /> + </ItemGroup> + <ItemGroup> + <None Include="packages.config" /> + </ItemGroup> + <ItemGroup> + <AppxManifest Include="Package.appxmanifest" /> + </ItemGroup> +</Project> \ No newline at end of file diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/MainPage.xaml b/Samples/WinUI/ConditionalPredicate/cpp-winui/MainPage.xaml new file mode 100644 index 000000000..4f541755b --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/MainPage.xaml @@ -0,0 +1,29 @@ +<!-- Copyright (c) Microsoft Corporation. + Licensed under the MIT License. --> +<Page + x:Class="ConditionalXamlPredicate.MainPage" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:local="using:ConditionalXamlPredicate" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + mc:Ignorable="d"> + + <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> + <NavigationView x:Name="NavView" + Loaded="NavView_Loaded" + ItemInvoked="NavView_ItemInvoked" + BackRequested="NavView_BackRequested"> + <NavigationView.MenuItems> + <NavigationViewItemHeader x:Name="MainPagesHeader" Content="Scenarios"/> + </NavigationView.MenuItems> + + <Grid RowDefinitions="*,Auto"> + <ScrollViewer> + <Frame Padding="50" x:Name="ContentFrame" Navigated="ContentFrame_Navigated" /> + </ScrollViewer> + <InfoBar x:Name="infoBar" Grid.Row="1" /> + </Grid> + </NavigationView> + </Grid> +</Page> diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/MainPage.xaml.cpp b/Samples/WinUI/ConditionalPredicate/cpp-winui/MainPage.xaml.cpp new file mode 100644 index 000000000..5039ceb0f --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/MainPage.xaml.cpp @@ -0,0 +1,156 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "pch.h" +#include "MainPage.xaml.h" +#if __has_include("MainPage.g.cpp") +#include "MainPage.g.cpp" +#endif + +namespace winrt +{ + using namespace Microsoft::UI::Xaml; + using namespace Microsoft::UI::Xaml::Controls; + using namespace Microsoft::UI::Xaml::Media; + using namespace Microsoft::UI::Xaml::Media::Animation; + using namespace Microsoft::UI::Xaml::Navigation; + using namespace Windows::UI::Xaml::Interop; +} + +namespace winrt::ConditionalXamlPredicate::implementation +{ + ConditionalXamlPredicate::MainPage MainPage::current{ nullptr }; + + MainPage::MainPage() + { + InitializeComponent(); + MainPage::current = *this; + } + + void MainPage::NotifyUser(hstring const& strMessage, InfoBarSeverity const& severity) + { + // If called from the UI thread, then update immediately. + // Otherwise, schedule a task on the UI thread to perform the update. + if (this->DispatcherQueue().HasThreadAccess()) + { + UpdateStatus(strMessage, severity); + } + else + { + DispatcherQueue().TryEnqueue([strongThis = get_strong(), this, strMessage, severity] + { UpdateStatus(strMessage, severity); }); + } + } + + void MainPage::UpdateStatus(hstring const& strMessage, InfoBarSeverity severity) + { + infoBar().Message(strMessage); + infoBar().IsOpen(!strMessage.empty()); + infoBar().Severity(severity); + } + + void MainPage::NavView_Loaded(IInspectable const&, RoutedEventArgs const&) + { + for (auto&& s : Scenarios()) + { + FontIcon fontIcon{}; + fontIcon.FontFamily(winrt::FontFamily(L"Segoe MDL2 Assets")); + fontIcon.Glyph(L"\uE82D"); + + NavigationViewItem navViewItem{}; + navViewItem.Content(box_value(s.Title)); + navViewItem.Tag(box_value(s.ClassName)); + navViewItem.Icon(fontIcon); + NavView().MenuItems().Append(navViewItem); + } + + // NavView doesn't load any page by default, so load home page. + NavView().SelectedItem(NavView().MenuItems().GetAt(0)); + + // If navigation occurs on SelectionChanged, this isn't needed. + // Because we use ItemInvoked to navigate, we need to call Navigate + // here to load the home page. + if (Scenarios().Size() > 0) + { + NavView_Navigate(Scenarios().GetAt(0).ClassName, nullptr); + } + } + + + void MainPage::NavView_ItemInvoked(NavigationView const&, NavigationViewItemInvokedEventArgs const& args) + { + if (args.IsSettingsInvoked() == true) + { + hstring xamltypename = winrt::xaml_typename<SettingsPage>().Name; + NavView_Navigate(xamltypename, args.RecommendedNavigationTransitionInfo()); + } + else if (args.InvokedItemContainer() != nullptr) + { + auto navItemTag = winrt::unbox_value<hstring>(args.InvokedItemContainer().Tag()); + if (navItemTag != L"") + { + NavView_Navigate(navItemTag, args.RecommendedNavigationTransitionInfo()); + } + } + } + + void MainPage::NavView_Navigate(hstring navItemTag, NavigationTransitionInfo const&) + { + TypeName pageType; + + if (navItemTag == winrt::xaml_typename<SettingsPage>().Name) + { + pageType = winrt::xaml_typename<SettingsPage>(); + } + else + { + pageType.Name = navItemTag; + pageType.Kind = TypeKind::Metadata; + } + + // Get the page type before navigation so you can prevent duplicate + // entries in the backstack. + TypeName prePageType = ContentFrame().CurrentSourcePageType(); + + // Only navigate if the selected page isn't currently loaded. + if (prePageType.Name != pageType.Name) + { + DrillInNavigationTransitionInfo drillIn; + ContentFrame().Navigate(pageType, nullptr, drillIn); + } + } + + void MainPage::NavView_BackRequested(NavigationView const&, NavigationViewBackRequestedEventArgs const&) + { + if (ContentFrame().CanGoBack()) + { + ContentFrame().GoBack(); + } + } + + void MainPage::ContentFrame_Navigated(IInspectable const&, NavigationEventArgs const& e) + { + NavView().IsBackEnabled(ContentFrame().CanGoBack()); + + if (ContentFrame().SourcePageType().Name == winrt::xaml_typename<SettingsPage>().Name) + { + // SettingsItem is not part of NavView.MenuItems, and doesn't have a Tag. + NavView().SelectedItem((NavView().SettingsItem().as<NavigationViewItem>())); + NavView().Header(winrt::box_value(L"Settings")); + } + else + { + for (auto&& item : NavView().MenuItems()) + { + auto navViewItem = item.try_as<NavigationViewItem>(); + if (navViewItem != nullptr && + winrt::unbox_value<hstring>(navViewItem.Tag()) == e.SourcePageType().Name) + { + NavView().SelectedItem(navViewItem); + NavView().Header(navViewItem.Content()); + break; + } + } + } + } +} diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/MainPage.xaml.h b/Samples/WinUI/ConditionalPredicate/cpp-winui/MainPage.xaml.h new file mode 100644 index 000000000..fe10bd1a3 --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/MainPage.xaml.h @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once +#include "MainPage.g.h" + +namespace winrt::ConditionalXamlPredicate::implementation +{ + struct MainPage : MainPageT<MainPage> + { + MainPage(); + static ConditionalXamlPredicate::MainPage Current() { return current; } + static Windows::Foundation::Collections::IVector<ConditionalXamlPredicate::Scenario> Scenarios() { return scenariosInner; } + void NotifyUser(hstring const& strMessage, Microsoft::UI::Xaml::Controls::InfoBarSeverity const& severity); + void UpdateStatus(hstring const& strMessage, Microsoft::UI::Xaml::Controls::InfoBarSeverity severity); + void NavView_Loaded(Windows::Foundation::IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& e); + void NavView_ItemInvoked(Microsoft::UI::Xaml::Controls::NavigationView const& sender, Microsoft::UI::Xaml::Controls::NavigationViewItemInvokedEventArgs const& args); + void NavView_Navigate(hstring navItemTag, Microsoft::UI::Xaml::Media::Animation::NavigationTransitionInfo const& transitionInfo); + void NavView_BackRequested(Microsoft::UI::Xaml::Controls::NavigationView const& sender, Microsoft::UI::Xaml::Controls::NavigationViewBackRequestedEventArgs const& args); + void ContentFrame_Navigated(Windows::Foundation::IInspectable const& sender, Microsoft::UI::Xaml::Navigation::NavigationEventArgs const& e); + + private: + static Windows::Foundation::Collections::IVector<Scenario> scenariosInner; + static ConditionalXamlPredicate::MainPage current; + }; +} + +namespace winrt::ConditionalXamlPredicate::factory_implementation +{ + struct MainPage : MainPageT<MainPage, implementation::MainPage> + { + }; +} diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/MainWindow.xaml b/Samples/WinUI/ConditionalPredicate/cpp-winui/MainWindow.xaml new file mode 100644 index 000000000..92988d0ca --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/MainWindow.xaml @@ -0,0 +1,13 @@ +<!-- Copyright (c) Microsoft Corporation. + Licensed under the MIT License. --> +<Window + x:Class="ConditionalXamlPredicate.MainWindow" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:local="using:ConditionalXamlPredicate" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + mc:Ignorable="d"> + + <local:MainPage/> +</Window> diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/MainWindow.xaml.cpp b/Samples/WinUI/ConditionalPredicate/cpp-winui/MainWindow.xaml.cpp new file mode 100644 index 000000000..0170484b9 --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/MainWindow.xaml.cpp @@ -0,0 +1,89 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "pch.h" +#include "MainWindow.xaml.h" +#if __has_include("MainWindow.g.cpp") +#include "MainWindow.g.cpp" + +#include "microsoft.ui.xaml.window.h" +#include "SampleConfiguration.h" +#endif + +namespace winrt +{ + using namespace Microsoft::UI::Xaml; +} + +namespace winrt::ConditionalXamlPredicate::implementation +{ + MainWindow::MainWindow() + { + InitializeComponent(); + + Title(winrt::ConditionalXamlPredicate::SampleConfig::FeatureName); + + HWND hwnd = GetWindowHandle(); + LoadIcon(hwnd, L"windows-sdk.ico"); + SetWindowSize(hwnd, 1050, 800); + PlacementCenterWindowInMonitorWin32(hwnd); + } + + HWND MainWindow::GetWindowHandle() + { + if (_hwnd == nullptr) + { + Window window = *this; + window.as<IWindowNative>()->get_WindowHandle(&_hwnd); + } + return _hwnd; + } + + void MainWindow::LoadIcon(HWND hwnd, wchar_t const* iconPath) + { + HANDLE hSmallIcon = LoadImageW(nullptr, iconPath, IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), + LR_LOADFROMFILE | LR_SHARED); + SendMessageW(hwnd, WM_SETICON, ICON_SMALL, reinterpret_cast<LPARAM>(hSmallIcon)); + + HANDLE hBigIcon = LoadImageW(nullptr, iconPath, IMAGE_ICON, + GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), + LR_LOADFROMFILE | LR_SHARED); + SendMessageW(hwnd, WM_SETICON, ICON_BIG, reinterpret_cast<LPARAM>(hBigIcon)); + } + + void MainWindow::SetWindowSize(HWND hwnd, int width, int height) + { + // Win32 uses pixels and WinUI 3 uses effective pixels, so you should apply the DPI scale factor + const UINT dpi = GetDpiForWindow(hwnd); + const float scalingFactor = static_cast<float>(dpi) / 96; + const int widthScaled = static_cast<int>(width * scalingFactor); + const int heightScaled = static_cast<int>(height * scalingFactor); + + SetWindowPos(hwnd, nullptr, 0, 0, widthScaled, heightScaled, SWP_NOMOVE | SWP_NOZORDER); + } + + void MainWindow::PlacementCenterWindowInMonitorWin32(HWND hwnd) + { + RECT windowMontiorRectToAdjust; + GetWindowRect(hwnd, &windowMontiorRectToAdjust); + ClipOrCenterRectToMonitorWin32(windowMontiorRectToAdjust); + SetWindowPos(hwnd, nullptr, windowMontiorRectToAdjust.left, + windowMontiorRectToAdjust.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); + } + + void MainWindow::ClipOrCenterRectToMonitorWin32(RECT& adjustedWindowRect) + { + MONITORINFO mi{ sizeof(mi) }; + GetMonitorInfoW(MonitorFromRect(&adjustedWindowRect, MONITOR_DEFAULTTONEAREST), &mi); + + const auto& rcWork = mi.rcWork; + const int w = adjustedWindowRect.right - adjustedWindowRect.left; + const int h = adjustedWindowRect.bottom - adjustedWindowRect.top; + + adjustedWindowRect.left = rcWork.left + (rcWork.right - rcWork.left - w) / 2; + adjustedWindowRect.top = rcWork.top + (rcWork.bottom - rcWork.top - h) / 2; + adjustedWindowRect.right = adjustedWindowRect.left + w; + adjustedWindowRect.bottom = adjustedWindowRect.top + h; + } +} diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/MainWindow.xaml.h b/Samples/WinUI/ConditionalPredicate/cpp-winui/MainWindow.xaml.h new file mode 100644 index 000000000..8d897ab87 --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/MainWindow.xaml.h @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once +#include "MainWindow.g.h" +#include "pch.h" + +namespace winrt::ConditionalXamlPredicate::implementation +{ + struct MainWindow : MainWindowT<MainWindow> + { + MainWindow(); + + private: + HWND _hwnd{ nullptr }; + void SetWindowSize(HWND hwnd, const int width, const int height); + HWND GetWindowHandle(); + void LoadIcon(HWND hwnd, wchar_t const* iconName); + void ClipOrCenterRectToMonitorWin32(RECT& rc); + void PlacementCenterWindowInMonitorWin32(HWND hwnd); + }; +} + +namespace winrt::ConditionalXamlPredicate::factory_implementation +{ + struct MainWindow : MainWindowT<MainWindow, implementation::MainWindow> + { + }; +} diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/MyCustomPredicate.cpp b/Samples/WinUI/ConditionalPredicate/cpp-winui/MyCustomPredicate.cpp new file mode 100644 index 000000000..1a9424efa --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/MyCustomPredicate.cpp @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "pch.h" +#include "MyCustomPredicate.h" +#include "MyCustomPredicate.g.cpp" + +namespace winrt::ConditionalXamlPredicate::implementation +{ + bool MyCustomPredicate::Evaluate(winrt::Windows::Foundation::Collections::IVectorView<hstring> const& arguments) + { + auto argsCount = arguments.Size(); + if (argsCount >= 2) + { + hstring firstArg = arguments.GetAt(0); + hstring secondArg = arguments.GetAt(1); + if (firstArg == L"FeatureABC") + { + // For demo purpose, return true if second argument is "true", false otherwise + return secondArg == L"true"; + } + else if (firstArg == L"FeatureXYZ") + { + // Marking FeatureXYZ as disabled + return secondArg == L"false"; + } + } + throw hresult_not_implemented(); + } +} diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/MyCustomPredicate.h b/Samples/WinUI/ConditionalPredicate/cpp-winui/MyCustomPredicate.h new file mode 100644 index 000000000..8eb90ce85 --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/MyCustomPredicate.h @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once +#include "MyCustomPredicate.g.h" + +namespace winrt::ConditionalXamlPredicate::implementation +{ + struct MyCustomPredicate : MyCustomPredicateT<MyCustomPredicate> + { + MyCustomPredicate() = default; + + bool Evaluate(winrt::Windows::Foundation::Collections::IVectorView<hstring> const& arguments); + }; +} +namespace winrt::ConditionalXamlPredicate::factory_implementation +{ + struct MyCustomPredicate : MyCustomPredicateT<MyCustomPredicate, implementation::MyCustomPredicate> + { + }; +} \ No newline at end of file diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/Package.appxmanifest b/Samples/WinUI/ConditionalPredicate/cpp-winui/Package.appxmanifest new file mode 100644 index 000000000..aec4b383e --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/Package.appxmanifest @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> + +<Package + xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" + xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" + xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" + IgnorableNamespaces="uap rescap"> + + <Identity + Name="055cd150-3243-4ad5-a957-dfd0af1d3b05" + Publisher="CN=Microsoft Corporation" + Version="1.0.0.0" /> + + <Properties> + <DisplayName>ConditionalXamlPredicate</DisplayName> + <PublisherDisplayName>Microsoft Corporation</PublisherDisplayName> + <Logo>Assets\logo.png</Logo> + </Properties> + + <Dependencies> + <TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" /> + <TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" /> + </Dependencies> + + <Resources> + <Resource Language="x-generate"/> + </Resources> + + <Applications> + <Application Id="App" + Executable="$targetnametoken$.exe" + EntryPoint="$targetentrypoint$"> + <uap:VisualElements + DisplayName="ConditionalXamlPredicate Windows App SDK C++ WinUI Sample" + Description="ConditionalXamlPredicate Windows App SDK C++ WinUI Sample" + BackgroundColor="transparent" + Square150x150Logo="Assets\Square150x150Logo.png" Square44x44Logo="Assets\Square44x44Logo.png"> + <uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png" /> + <uap:SplashScreen Image="Assets\SplashScreen.png" /> + </uap:VisualElements> + </Application> + </Applications> + + <Capabilities> + <rescap:Capability Name="runFullTrust" /> + </Capabilities> +</Package> diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/Project.idl b/Samples/WinUI/ConditionalPredicate/cpp-winui/Project.idl new file mode 100644 index 000000000..7b5886e10 --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/Project.idl @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace ConditionalXamlPredicate +{ + /* The following code is scenario/feature-specific IDL. + Samples authors should modify these runtime classes as appropriate. */ + + [default_interface] + runtimeclass Scenario1_LoadConditionalControls : Microsoft.UI.Xaml.Controls.Page + { + Scenario1_LoadConditionalControls(); + } + + [default_interface] + runtimeclass Scenario2_ConditionalArguments : Microsoft.UI.Xaml.Controls.Page + { + Scenario2_ConditionalArguments(); + } + + [default_interface] + [bindable] + runtimeclass MyCustomPredicate : Microsoft.UI.Xaml.DependencyObject, Microsoft.UI.Xaml.Markup.IXamlPredicate + { + MyCustomPredicate(); + } + + /* The following code is template-specific IDL. + These runtime classes are the same across all C++/WinRT WinUI samples. */ + + runtimeclass MainPage : Microsoft.UI.Xaml.Controls.Page + { + MainPage(); + static MainPage Current(); + void NotifyUser(String strMessage, Microsoft.UI.Xaml.Controls.InfoBarSeverity severity); + } + + // To use Scenario in a winrt::Windows::Foundation::Collections::IVector<Scenario>, Scenario should be a WinRT type + struct Scenario + { + String Title; + String ClassName; + }; + + [default_interface] + runtimeclass MainWindow : Microsoft.UI.Xaml.Window + { + MainWindow(); + } + + [default_interface] + runtimeclass SettingsPage : Microsoft.UI.Xaml.Controls.Page + { + SettingsPage(); + } +} diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/SampleConfiguration.cpp b/Samples/WinUI/ConditionalPredicate/cpp-winui/SampleConfiguration.cpp new file mode 100644 index 000000000..bbfac3b24 --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/SampleConfiguration.cpp @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once +#include "pch.h" +#include "SampleConfiguration.h" +#include "MainPage.xaml.h" + +namespace winrt +{ + using namespace Microsoft::UI::Xaml; + using namespace Windows::Foundation::Collections; +} + +namespace winrt::ConditionalXamlPredicate +{ + IVector<Scenario> implementation::MainPage::scenariosInner = single_threaded_observable_vector<Scenario>( + { + Scenario{ L"Load Conditional Controls", hstring(name_of<ConditionalXamlPredicate::Scenario1_LoadConditionalControls>())}, + Scenario{ L"Conditional Arguments", hstring(name_of<ConditionalXamlPredicate::Scenario2_ConditionalArguments>())}, + }); + + hstring SampleConfig::FeatureName{ L"ConditionalXamlPredicate" }; + ElementTheme SampleConfig::CurrentTheme{ ElementTheme::Default }; +} diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/SampleConfiguration.h b/Samples/WinUI/ConditionalPredicate/cpp-winui/SampleConfiguration.h new file mode 100644 index 000000000..c770b0715 --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/SampleConfiguration.h @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once +#include "pch.h" + +namespace winrt::ConditionalXamlPredicate +{ + struct SampleConfig + { + public: + static hstring FeatureName; + static Microsoft::UI::Xaml::ElementTheme CurrentTheme; + }; +} diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/Scenario1_LoadConditionalControls.xaml b/Samples/WinUI/ConditionalPredicate/cpp-winui/Scenario1_LoadConditionalControls.xaml new file mode 100644 index 000000000..6370aa890 --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/Scenario1_LoadConditionalControls.xaml @@ -0,0 +1,66 @@ +<!-- Copyright (c) Microsoft Corporation. + Licensed under the MIT License. --> +<Page + x:Class="ConditionalXamlPredicate.Scenario1_LoadConditionalControls" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:local="using:ConditionalXamlPredicate" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:featureABCEnabled="http://schemas.microsoft.com/winfx/2006/xaml/presentation?local:MyCustomPredicate(FeatureABC,true)" + xmlns:featureABCDisabled="http://schemas.microsoft.com/winfx/2006/xaml/presentation?local:MyCustomPredicate(FeatureABC,false)" + xmlns:featureXYZEnabled="http://schemas.microsoft.com/winfx/2006/xaml/presentation?local:MyCustomPredicate(FeatureXYZ,true)" + xmlns:featureXYZDisabled="http://schemas.microsoft.com/winfx/2006/xaml/presentation?local:MyCustomPredicate(FeatureXYZ,false)" + mc:Ignorable="d"> + + <Grid RowDefinitions="*,Auto"> + <ScrollViewer Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> + <StackPanel Spacing="10" Margin="10,10,10,10"> + <TextBlock Text="Description:" Style="{StaticResource SampleHeaderTextStyle}"/> + <TextBlock Style="{StaticResource ScenarioDescriptionTextStyle}" TextWrapping="Wrap"> + This scenario demonstrates conditional XAML loading using custom predicates. + Controls below are conditionally loaded based on the FeatureABC flag. + </TextBlock> + + <!-- Controls visible when FeatureABC is ENABLED --> + <featureABCEnabled:TextBlock Text="FeatureABC is ENABLED" + Foreground="Green" FontWeight="Bold"/> + <featureABCEnabled:Button Content="ABC Feature Action" /> + + <!-- Controls visible when FeatureABC is DISABLED --> + <featureABCDisabled:TextBlock Text="FeatureABC is DISABLED" + Foreground="Red" FontWeight="Bold"/> + <featureABCDisabled:Button Content="ABC Fallback Action" /> + + <!-- Controls visible when FeatureXYZ is ENABLED --> + <featureXYZEnabled:TextBlock Text="FeatureXYZ is ENABLED" + Foreground="Blue" FontWeight="Bold"/> + <featureXYZEnabled:Button Content="XYZ Feature Action" /> + + <!-- Controls visible when FeatureXYZ is DISABLED --> + <featureXYZDisabled:TextBlock Text="FeatureXYZ is DISABLED" + Foreground="Gray" FontWeight="Bold"/> + <featureXYZDisabled:Button Content="XYZ Fallback Action" /> + + <!-- Nested example: Parent always visible, children conditional --> + <Border BorderBrush="Gray" BorderThickness="1" Padding="10" Margin="0,10,0,0"> + <StackPanel Spacing="5"> + <TextBlock Text="Nested Controls Demo" FontWeight="Bold"/> + + <!-- Parent control under FeatureABC, with nested children under FeatureXYZ --> + <featureABCEnabled:StackPanel Margin="10,0,0,0"> + <TextBlock Text="ABC is enabled (parent)" Foreground="Green"/> + + <!-- Nested children: only loaded if ABC is enabled AND XYZ condition met --> + <featureXYZEnabled:TextBlock Text=" - XYZ is also enabled (child)" Foreground="Blue" Margin="10,0,0,0"/> + <featureXYZDisabled:TextBlock Text=" - XYZ is disabled (child)" Foreground="Gray" Margin="10,0,0,0"/> + </featureABCEnabled:StackPanel> + + <featureABCDisabled:TextBlock Text="ABC is disabled" Foreground="Red" Margin="10,0,0,0"/> + </StackPanel> + </Border> + + </StackPanel> + </ScrollViewer> + </Grid> +</Page> diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/Scenario1_LoadConditionalControls.xaml.cpp b/Samples/WinUI/ConditionalPredicate/cpp-winui/Scenario1_LoadConditionalControls.xaml.cpp new file mode 100644 index 000000000..a14525e2d --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/Scenario1_LoadConditionalControls.xaml.cpp @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "pch.h" +#include "Scenario1_LoadConditionalControls.xaml.h" +#if __has_include("Scenario1_LoadConditionalControls.g.cpp") +#include "Scenario1_LoadConditionalControls.g.cpp" +#endif + +namespace winrt +{ + using namespace Microsoft::UI::Xaml; + using namespace Microsoft::UI::Xaml::Controls; + using namespace Windows::Foundation; +} + +namespace winrt::ConditionalXamlPredicate::implementation +{ + MainPage Scenario1_LoadConditionalControls::rootPage{ nullptr }; + + Scenario1_LoadConditionalControls::Scenario1_LoadConditionalControls() + { + InitializeComponent(); + Scenario1_LoadConditionalControls::rootPage = MainPage::Current(); + } +} diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/Scenario1_LoadConditionalControls.xaml.h b/Samples/WinUI/ConditionalPredicate/cpp-winui/Scenario1_LoadConditionalControls.xaml.h new file mode 100644 index 000000000..7aea1ca0e --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/Scenario1_LoadConditionalControls.xaml.h @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +#include "Scenario1_LoadConditionalControls.g.h" + +namespace winrt::ConditionalXamlPredicate::implementation +{ + struct Scenario1_LoadConditionalControls : Scenario1_LoadConditionalControlsT<Scenario1_LoadConditionalControls> + { + Scenario1_LoadConditionalControls(); + private: + static ConditionalXamlPredicate::MainPage rootPage; + }; +} + +namespace winrt::ConditionalXamlPredicate::factory_implementation +{ + struct Scenario1_LoadConditionalControls : Scenario1_LoadConditionalControlsT<Scenario1_LoadConditionalControls, implementation::Scenario1_LoadConditionalControls> + { + }; +} diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/Scenario2_ConditionalArguments.xaml b/Samples/WinUI/ConditionalPredicate/cpp-winui/Scenario2_ConditionalArguments.xaml new file mode 100644 index 000000000..c69c02cd3 --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/Scenario2_ConditionalArguments.xaml @@ -0,0 +1,77 @@ +<!-- Copyright (c) Microsoft Corporation. + Licensed under the MIT License. --> +<Page + x:Class="ConditionalXamlPredicate.Scenario2_ConditionalArguments" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:local="using:ConditionalXamlPredicate" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:featureABCEnabled="http://schemas.microsoft.com/winfx/2006/xaml/presentation?local:MyCustomPredicate(FeatureABC,true)" + xmlns:featureABCDisabled="http://schemas.microsoft.com/winfx/2006/xaml/presentation?local:MyCustomPredicate(FeatureABC,false)" + xmlns:featureXYZEnabled="http://schemas.microsoft.com/winfx/2006/xaml/presentation?local:MyCustomPredicate(FeatureXYZ,true)" + xmlns:featureXYZDisabled="http://schemas.microsoft.com/winfx/2006/xaml/presentation?local:MyCustomPredicate(FeatureXYZ,false)" + mc:Ignorable="d"> + + <Grid> + <ScrollViewer Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> + <StackPanel Spacing="10" Margin="10,10,10,10"> + <TextBlock Text="Description:" Style="{StaticResource ScenarioHeaderTextStyle}"/> + <TextBlock Style="{StaticResource ScenarioDescriptionTextStyle}" TextWrapping="Wrap"> + This scenario demonstrates conditional XAML on property level. + The same control can have different property values based on feature flags. + </TextBlock> + + <!-- FeatureABC: Conditional Foreground property --> + <TextBlock Text="This text color depends on FeatureABC" + featureABCEnabled:Foreground="Green" + featureABCDisabled:Foreground="Red"/> + + <!-- FeatureABC: Conditional Background property --> + <Border Padding="10" + featureABCEnabled:Background="LightGreen" + featureABCDisabled:Background="LightCoral"> + <TextBlock Text="Border background depends on FeatureABC"/> + </Border> + + <!-- FeatureXYZ: Conditional Foreground property --> + <TextBlock Text="This text color depends on FeatureXYZ" + featureXYZEnabled:Foreground="Blue" + featureXYZDisabled:Foreground="Gray"/> + + <!-- FeatureXYZ: Conditional Background property --> + <Border Padding="10" + featureXYZEnabled:Background="LightBlue" + featureXYZDisabled:Background="LightGray"> + <TextBlock Text="Border background depends on FeatureXYZ"/> + </Border> + + <!-- Multiple properties on same control with FeatureABC --> + <Button Content="Button styled by FeatureABC" + featureABCEnabled:Background="DarkGreen" + featureABCEnabled:Foreground="White" + featureABCDisabled:Background="DarkRed" + featureABCDisabled:Foreground="Yellow"/> + + <!-- Multiple properties on same control with FeatureXYZ --> + <Button Content="Button styled by FeatureXYZ" + featureXYZEnabled:Background="DarkBlue" + featureXYZEnabled:Foreground="White" + featureXYZDisabled:Background="DarkGray" + featureXYZDisabled:Foreground="Black"/> + + <!-- Mixed: Different properties controlled by different features --> + <Border Padding="10" BorderThickness="2" + featureABCEnabled:Background="LightGreen" + featureABCDisabled:Background="LightCoral" + featureXYZEnabled:BorderBrush="Blue" + featureXYZDisabled:BorderBrush="Gray"> + <TextBlock Text="Background by FeatureABC, Border by FeatureXYZ" + featureABCEnabled:Foreground="DarkGreen" + featureABCDisabled:Foreground="DarkRed"/> + </Border> + + </StackPanel> + </ScrollViewer> + </Grid> +</Page> diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/Scenario2_ConditionalArguments.xaml.cpp b/Samples/WinUI/ConditionalPredicate/cpp-winui/Scenario2_ConditionalArguments.xaml.cpp new file mode 100644 index 000000000..6eca0da9a --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/Scenario2_ConditionalArguments.xaml.cpp @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "pch.h" +#include "Scenario2_ConditionalArguments.xaml.h" +#if __has_include("Scenario2_ConditionalArguments.g.cpp") +#include "Scenario2_ConditionalArguments.g.cpp" +#endif + +namespace winrt +{ + using namespace Microsoft::UI::Xaml; +} + +// To learn more about WinUI, the WinUI project structure, +// and more about our project templates, see: http://aka.ms/winui-project-info. + +namespace winrt::ConditionalXamlPredicate::implementation +{ + Scenario2_ConditionalArguments::Scenario2_ConditionalArguments() + { + InitializeComponent(); + } +} diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/Scenario2_ConditionalArguments.xaml.h b/Samples/WinUI/ConditionalPredicate/cpp-winui/Scenario2_ConditionalArguments.xaml.h new file mode 100644 index 000000000..d960d5774 --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/Scenario2_ConditionalArguments.xaml.h @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +#include "Scenario2_ConditionalArguments.g.h" + +namespace winrt::ConditionalXamlPredicate::implementation +{ + struct Scenario2_ConditionalArguments : Scenario2_ConditionalArgumentsT<Scenario2_ConditionalArguments> + { + Scenario2_ConditionalArguments(); + }; +} + +namespace winrt::ConditionalXamlPredicate::factory_implementation +{ + struct Scenario2_ConditionalArguments : Scenario2_ConditionalArgumentsT<Scenario2_ConditionalArguments, implementation::Scenario2_ConditionalArguments> + { + }; +} diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/SettingsPage.xaml b/Samples/WinUI/ConditionalPredicate/cpp-winui/SettingsPage.xaml new file mode 100644 index 000000000..cb9e29920 --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/SettingsPage.xaml @@ -0,0 +1,40 @@ +<!-- Copyright (c) Microsoft Corporation. + Licensed under the MIT License. --> +<Page + x:Class="ConditionalXamlPredicate.SettingsPage" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:local="using:ConditionalXamlPredicate" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + mc:Ignorable="d"> + + <Grid RowDefinitions="*,Auto"> + <ScrollViewer Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> + <StackPanel Spacing="10" Margin="10,10,10,10" > + <TextBlock Text="Theme Mode" Style="{StaticResource SampleHeaderTextStyle}"/> + <StackPanel x:Name="themePanel"> + <RadioButton Checked="OnThemeRadioButtonChecked" Content="Light"> + <RadioButton.Tag> + <ElementTheme>Light</ElementTheme> + </RadioButton.Tag> + </RadioButton> + <RadioButton Checked="OnThemeRadioButtonChecked" Content="Dark"> + <RadioButton.Tag> + <ElementTheme>Dark</ElementTheme> + </RadioButton.Tag> + </RadioButton> + <RadioButton Checked="OnThemeRadioButtonChecked" Content="System Default"> + <RadioButton.Tag> + <ElementTheme>Default</ElementTheme> + </RadioButton.Tag> + </RadioButton> + </StackPanel> + </StackPanel> + </ScrollViewer> + + <StackPanel Spacing="10" Margin="10,10,10,10" Orientation="Vertical" VerticalAlignment="Bottom" Grid.Row="0"> + <TextBlock Text="© Microsoft Corporation. All rights reserved." Style="{StaticResource CopyrightTextStyle}" TextWrapping="Wrap"/> + </StackPanel> + </Grid> +</Page> diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/SettingsPage.xaml.cpp b/Samples/WinUI/ConditionalPredicate/cpp-winui/SettingsPage.xaml.cpp new file mode 100644 index 000000000..feb994928 --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/SettingsPage.xaml.cpp @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "pch.h" +#include "SettingsPage.xaml.h" +#if __has_include("SettingsPage.g.cpp") +#include "SettingsPage.g.cpp" +#endif +#include <SampleConfiguration.h> + +namespace winrt +{ + using namespace Microsoft::UI::Xaml; + using namespace Microsoft::UI::Xaml::Controls; + using namespace Microsoft::UI::Xaml::Navigation; + using namespace Windows::Foundation; +} + +namespace winrt::ConditionalXamlPredicate::implementation +{ + SettingsPage::SettingsPage() + { + InitializeComponent(); + } + + void SettingsPage::OnNavigatedTo(NavigationEventArgs const&) + { + for (UIElement&& c : themePanel().Children()) + { + auto tag = c.as<RadioButton>().Tag().as<ElementTheme>(); + if (tag == SampleConfig::CurrentTheme) + { + auto radioButton = c.as<RadioButton>(); + radioButton.IsChecked(true); + } + } + } + + void SettingsPage::OnThemeRadioButtonChecked(IInspectable const& sender, RoutedEventArgs const&) + { + auto radiobutton = sender.as<RadioButton>(); + auto selectedTheme = unbox_value<ElementTheme>(radiobutton.Tag()); + + auto content = MainPage::Current().Content().as<Grid>(); + if (content != nullptr) + { + content.RequestedTheme(selectedTheme); + SampleConfig::CurrentTheme = content.RequestedTheme(); + } + } +} diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/SettingsPage.xaml.h b/Samples/WinUI/ConditionalPredicate/cpp-winui/SettingsPage.xaml.h new file mode 100644 index 000000000..783997c91 --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/SettingsPage.xaml.h @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +#include "SettingsPage.g.h" + +namespace winrt::ConditionalXamlPredicate::implementation +{ + struct SettingsPage : SettingsPageT<SettingsPage> + { + SettingsPage(); + void OnNavigatedTo(Microsoft::UI::Xaml::Navigation::NavigationEventArgs const& e); + void OnThemeRadioButtonChecked(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e); + }; +} + +namespace winrt::ConditionalXamlPredicate::factory_implementation +{ + struct SettingsPage : SettingsPageT<SettingsPage, implementation::SettingsPage> + { + }; +} diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/Styles.xaml b/Samples/WinUI/ConditionalPredicate/cpp-winui/Styles.xaml new file mode 100644 index 000000000..5c9e0ec2e --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/Styles.xaml @@ -0,0 +1,132 @@ +<!-- Copyright (c) Microsoft Corporation. + Licensed under the MIT License. --> +<ResourceDictionary + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:local="using:ConditionalXamlPredicate"> + + <ResourceDictionary.MergedDictionaries> + <XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" /> + <!-- Other merged dictionaries here --> + </ResourceDictionary.MergedDictionaries> + <!-- Other app resources here --> + + <Style x:Key="SymbolButton" TargetType="ToggleButton"> + <Setter Property="FontSize" Value="16" /> + <Setter Property="FontFamily" Value="{StaticResource SymbolThemeFontFamily}" /> + <Setter Property="MinHeight" Value="48" /> + <Setter Property="MinWidth" Value="48" /> + <Setter Property="Margin" Value="0,4,0,0" /> + <Setter Property="Padding" Value="0" /> + <Setter Property="HorizontalAlignment" Value="Left" /> + <Setter Property="VerticalAlignment" Value="Top" /> + <Setter Property="HorizontalContentAlignment" Value="Center" /> + <Setter Property="VerticalContentAlignment" Value="Center" /> + <Setter Property="Background" Value="Transparent" /> + <Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseHighBrush}" /> + <Setter Property="Content" Value="" /> + <Setter Property="AutomationProperties.Name" Value="Menu" /> + <Setter Property="UseSystemFocusVisuals" Value="True" /> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="ToggleButton"> + <Grid x:Name="LayoutRoot" + Background="{TemplateBinding Background}"> + <VisualStateManager.VisualStateGroups> + <VisualStateGroup x:Name="CommonStates"> + <VisualState x:Name="Normal" /> + <VisualState x:Name="PointerOver"> + <Storyboard> + <ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(Grid.Background)"> + <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListLowBrush}"/> + </ObjectAnimationUsingKeyFrames> + <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground"> + <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}"/> + </ObjectAnimationUsingKeyFrames> + </Storyboard> + </VisualState> + <VisualState x:Name="Pressed"> + <Storyboard> + <ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(Grid.Background)"> + <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListMediumBrush}"/> + </ObjectAnimationUsingKeyFrames> + <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground"> + <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}"/> + </ObjectAnimationUsingKeyFrames> + </Storyboard> + </VisualState> + <VisualState x:Name="Disabled"> + <Storyboard> + <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="(TextBlock.Foreground)"> + <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseLowBrush}"/> + </ObjectAnimationUsingKeyFrames> + </Storyboard> + </VisualState> + <VisualState x:Name="Checked"/> + <VisualState x:Name="CheckedPointerOver"> + <Storyboard> + <ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(Grid.Background)"> + <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListLowBrush}"/> + </ObjectAnimationUsingKeyFrames> + <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground"> + <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}"/> + </ObjectAnimationUsingKeyFrames> + </Storyboard> + </VisualState> + <VisualState x:Name="CheckedPressed"> + <Storyboard> + <ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(Grid.Background)"> + <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListMediumBrush}"/> + </ObjectAnimationUsingKeyFrames> + <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground"> + <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}"/> + </ObjectAnimationUsingKeyFrames> + </Storyboard> + </VisualState> + <VisualState x:Name="CheckedDisabled"> + <Storyboard> + <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="(TextBlock.Foreground)"> + <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseLowBrush}"/> + </ObjectAnimationUsingKeyFrames> + </Storyboard> + </VisualState> + </VisualStateGroup> + </VisualStateManager.VisualStateGroups> + <ContentPresenter x:Name="ContentPresenter" + Content="{TemplateBinding Content}" + Margin="{TemplateBinding Padding}" + HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" + VerticalAlignment="{TemplateBinding VerticalContentAlignment}" + AutomationProperties.AccessibilityView="Raw" /> + </Grid> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <Style x:Key="BasicTextStyle" TargetType="TextBlock" BasedOn="{StaticResource BodyTextBlockStyle}"> + <Setter Property="Margin" Value="0,0,0,12"/> + </Style> + + <Style x:Key="TagLineTextStyle" TargetType="TextBlock" BasedOn="{StaticResource BodyTextBlockStyle}"> + </Style> + + <Style x:Key="SampleHeaderTextStyle" TargetType="TextBlock" BasedOn="{StaticResource TitleTextBlockStyle}"> + <Setter Property="FontSize" Value="28"/> + </Style> + + <Style x:Key="CopyrightTextStyle" TargetType="TextBlock" BasedOn="{StaticResource BaseTextBlockStyle}"> + <Setter Property="FontWeight" Value="Normal"/> + </Style> + + <Style x:Key="ScenarioHeaderTextStyle" TargetType="TextBlock" BasedOn="{StaticResource TitleTextBlockStyle}"> + </Style> + + <Style x:Key="ScenarioDescriptionTextStyle" TargetType="TextBlock" BasedOn="{StaticResource BodyTextBlockStyle}"> + </Style> + + <Style x:Key="BaseMessageStyle" TargetType="TextBlock" BasedOn="{StaticResource BodyTextBlockStyle}"> + <Setter Property="Margin" Value="0,0,0,5"/> + </Style> + +</ResourceDictionary> diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/app.manifest b/Samples/WinUI/ConditionalPredicate/cpp-winui/app.manifest new file mode 100644 index 000000000..5d159b22b --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/app.manifest @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"> + <assemblyIdentity version="1.0.0.0" name="ConditionalXamlPredicate.app"/> + + <application xmlns="urn:schemas-microsoft-com:asm.v3"> + <windowsSettings> + <!-- The combination of below two tags have the following effect: + 1) Per-Monitor for >= Windows 10 Anniversary Update + 2) System < Windows 10 Anniversary Update + --> + <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware> + <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness> + </windowsSettings> + </application> +</assembly> diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/packages.config b/Samples/WinUI/ConditionalPredicate/cpp-winui/packages.config new file mode 100644 index 000000000..ba6704f1e --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/packages.config @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="Microsoft.Web.WebView2" version="1.0.3405.78" targetFramework="native" /> + <package id="Microsoft.Windows.CppWinRT" version="2.0.210922.5" targetFramework="native" /> + <package id="Microsoft.Windows.SDK.BuildTools" version="10.0.26100.4654" targetFramework="native" /> + <package id="Microsoft.Windows.SDK.BuildTools.MSIX" version="1.7.20250829.1" targetFramework="native" developmentDependency="true" /> + <package id="Microsoft.WindowsAppSDK" version="2.0.0-experimental4" targetFramework="native" /> + <package id="Microsoft.WindowsAppSDK.AI" version="2.0.130-experimental" targetFramework="native" /> + <package id="Microsoft.WindowsAppSDK.Base" version="2.0.1-experimental" targetFramework="native" /> + <package id="Microsoft.WindowsAppSDK.DWrite" version="2.0.1-experimental" targetFramework="native" /> + <package id="Microsoft.WindowsAppSDK.Foundation" version="2.0.11-experimental" targetFramework="native" /> + <package id="Microsoft.WindowsAppSDK.InteractiveExperiences" version="2.0.5-experimental" targetFramework="native" /> + <package id="Microsoft.WindowsAppSDK.ML" version="2.0.169-experimental" targetFramework="native" /> + <package id="Microsoft.WindowsAppSDK.Runtime" version="2.0.0-experimental4" targetFramework="native" /> + <package id="Microsoft.WindowsAppSDK.Widgets" version="2.0.3-experimental" targetFramework="native" /> + <package id="Microsoft.WindowsAppSDK.WinUI" version="2.0.4-experimental" targetFramework="native" /> +</packages> \ No newline at end of file diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/pch.cpp b/Samples/WinUI/ConditionalPredicate/cpp-winui/pch.cpp new file mode 100644 index 000000000..40e691ba7 --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/pch.cpp @@ -0,0 +1,4 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "pch.h" diff --git a/Samples/WinUI/ConditionalPredicate/cpp-winui/pch.h b/Samples/WinUI/ConditionalPredicate/cpp-winui/pch.h new file mode 100644 index 000000000..d84dd7c10 --- /dev/null +++ b/Samples/WinUI/ConditionalPredicate/cpp-winui/pch.h @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once +#include <windows.h> +#include <unknwn.h> +#include <restrictederrorinfo.h> +#include <hstring.h> + +// Undefine GetCurrentTime macro to prevent +// conflict with Storyboard::GetCurrentTime +#undef GetCurrentTime + +#include <winrt/Windows.Foundation.h> +#include <winrt/Windows.Foundation.Collections.h> +#include <winrt/Windows.ApplicationModel.Activation.h> +#include <winrt/Windows.UI.Xaml.Interop.h> //For using xaml_typename + +#include <winrt/Microsoft.UI.Composition.h> +#include <winrt/Microsoft.UI.Xaml.h> +#include <winrt/Microsoft.UI.Xaml.Controls.h> +#include <winrt/Microsoft.UI.Xaml.Media.Animation.h> +#include <winrt/Microsoft.UI.Xaml.Controls.Primitives.h> +#include <winrt/Microsoft.UI.Xaml.Data.h> +#include <winrt/Microsoft.UI.Xaml.Interop.h> +#include <winrt/Microsoft.UI.Xaml.Markup.h> +#include <winrt/Microsoft.UI.Xaml.Media.h> +#include <winrt/Microsoft.UI.Xaml.Navigation.h> +#include <winrt/Microsoft.UI.Xaml.Shapes.h> +#include <winrt/Microsoft.UI.Dispatching.h> +#include <winrt/Windows.UI.Core.h> + +#include "MyCustomPredicate.h" diff --git a/build.ps1 b/build.ps1 index 39ebffbd8..b28831298 100644 --- a/build.ps1 +++ b/build.ps1 @@ -100,9 +100,34 @@ function Get-Solutions { param([string]$SampleFilter) $targetRoot = $null; $solutions = @() if (-not [string]::IsNullOrWhiteSpace($SampleFilter)) { - $targetRoot = Join-Path $samplesRoot $SampleFilter - if (-not (Test-Path $targetRoot)) { Write-Error "Sample path not found: $targetRoot"; exit 1 } - $solutions = Get-ChildItem -Path $targetRoot -Filter *.sln -Recurse | Sort-Object FullName + # Check if input is an existing path + if (Test-Path $SampleFilter) { + $resolvedPath = (Resolve-Path $SampleFilter).Path + $samplesRootResolved = (Resolve-Path $samplesRoot).Path + # Reject paths outside samplesRoot + if (-not $resolvedPath.StartsWith($samplesRootResolved, [System.StringComparison]::OrdinalIgnoreCase)) { + Write-Error "Path must be under Samples root: $samplesRootResolved"; exit 1 + } + $probeDir = if (Test-Path $resolvedPath -PathType Container) { $resolvedPath } else { Split-Path -Parent $resolvedPath } + # Walk up to find .sln, stop at samplesRoot + while ($probeDir -and $probeDir.StartsWith($samplesRootResolved, [System.StringComparison]::OrdinalIgnoreCase)) { + $localSolutions = Get-ChildItem -Path $probeDir -Filter *.sln -File -ErrorAction SilentlyContinue | Sort-Object FullName + if ($localSolutions -and $localSolutions.Count -gt 0) { + Write-Host "Detected $($localSolutions.Count) solution(s) at: $probeDir" -ForegroundColor Yellow + return $localSolutions + } + $parent = Split-Path -Parent $probeDir + if ([string]::IsNullOrWhiteSpace($parent) -or $parent -eq $probeDir) { break } + $probeDir = $parent + } + Write-Warning "No solution found walking up from: $SampleFilter (stopped at Samples root)" + } + else { + # Treat as sample name; join with samplesRoot + $targetRoot = Join-Path $samplesRoot $SampleFilter + if (-not (Test-Path $targetRoot)) { Write-Error "Sample path not found: $targetRoot"; exit 1 } + $solutions = Get-ChildItem -Path $targetRoot -Filter *.sln -Recurse | Sort-Object FullName + } } else { $currentDir = Get-Location